Pregunta

Dado que los caracteres con y sin signo utilizan los mismos registros, etc., y simplemente interpretan los patrones de bits de manera diferente, y los caracteres C son básicamente solo caracteres de 8 bits, ¿cuál es la diferencia entre caracteres con y sin signo en C?Entiendo que la firma de char está definida por la implementación, y simplemente no puedo entender cómo podría marcar la diferencia, al menos cuando char se usa para contener cadenas en lugar de hacer matemáticas.

¿Fue útil?

Solución

No hará una diferencia para las cadenas. Pero en C puedes usar un personaje para hacer matemáticas, cuando hará la diferencia.

De hecho, cuando se trabaja en entornos de memoria restringidos, como las aplicaciones integradas de 8 bits, a menudo se usa un char para hacer matemáticas, y luego hace una gran diferencia. Esto se debe a que no hay un tipo byte por defecto en C.

Otros consejos

En términos de los valores que representan:

carácter sin firmar:

  • abarca el rango de valores 0..255 (00000000..11111111)
  • los valores se desbordan alrededor del borde bajo como:

    0 - 1 = 255 (00000000 - 00000001 = 11111111)

  • los valores se desbordan alrededor del borde superior como:

    255 + 1 = 0 (11111111 + 00000001 = 00000000)

  • el operador de desplazamiento a la derecha en modo bit (>>) realiza un desplazamiento lógico:

    10000000 >> 1 = 01000000 (128 / 2 = 64)

signo firmado:

  • abarca el rango de valores -128..127 (10000000..01111111)
  • los valores se desbordan alrededor del borde bajo como:

    -128 - 1 = 127 (10000000 - 00000001 = 01111111)

  • los valores se desbordan alrededor del borde superior como:

    127 + 1 = -128 (01111111 + 00000001 = 10000000)

  • el operador de desplazamiento a la derecha en modo bit (10000000 >> 1 = 11000000 (-128 / 2 = -64)) realiza un desplazamiento aritmético:

    <=>

Incluí las representaciones binarias para mostrar que el comportamiento de ajuste de valor es aritmética binaria pura y consistente y no tiene nada que ver con que un carácter sea firmado / no firmado (espere cambios a la derecha).

Update

Algunos comportamientos específicos de implementación mencionados en los comentarios:

#include <stdio.h>

int main(int argc, char** argv)
{
    char a = 'A';
    char b = 0xFF;
    signed char sa = 'A';
    signed char sb = 0xFF;
    unsigned char ua = 'A';
    unsigned char ub = 0xFF;
    printf("a > b: %s\n", a > b ? "true" : "false");
    printf("sa > sb: %s\n", sa > sb ? "true" : "false");
    printf("ua > ub: %s\n", ua > ub ? "true" : "false");
    return 0;
}


[root]# ./a.out
a > b: true
sa > sb: true
ua > ub: false

Es importante al ordenar cadenas.

Hay un par de diferencias. Lo que es más importante, si desborda el rango válido de un carácter asignándole un número entero demasiado grande o pequeño, y el carácter está firmado, el valor resultante está definido en la implementación o incluso podría aumentarse alguna señal (en C), como para todos los tipos con signo . Compare eso con el caso cuando asigna algo demasiado grande o pequeño a un carácter sin signo: el valor se ajusta, obtendrá una semántica definida con precisión. Por ejemplo, asignando un -1 a un personaje sin firmar, obtendrá un UCHAR_MAX. Por lo tanto, siempre que tenga un byte como en un número del 0 al 2 ^ CHAR_BIT, realmente debería usar un carácter sin signo para almacenarlo.

El signo también marca la diferencia al pasar a funciones vararg:

char c = getSomeCharacter(); // returns 0..255
printf("%d\n", c);

Suponga que el valor asignado a c sería demasiado grande para que lo represente char, y la máquina usa el complemento de dos. Muchas implementaciones se comportan en el caso de que asigne un valor demasiado grande al carácter, ya que el patrón de bits no cambiará. Si un int podrá representar todos los valores de char (que es para la mayoría de las implementaciones), entonces el char se está promoviendo a int antes de pasar a printf. Entonces, el valor de lo que se pasa sería negativo. Promover a int retendría ese signo. Entonces obtendrás un resultado negativo. Sin embargo, si char no está firmado, entonces el valor no está firmado, y la promoción a int producirá un int positivo. Puede usar caracteres sin signo, luego obtendrá un comportamiento definido con precisión tanto para la asignación a la variable como para pasar a printf, que luego imprimirá algo positivo.

Tenga en cuenta que un carácter, caracteres sin signo y con signo tienen al menos 8 bits de ancho. No es necesario que el carácter sea exactamente de 8 bits de ancho. Sin embargo, para la mayoría de los sistemas eso es cierto, pero para algunos, encontrará que usan caracteres de 32 bits. Un byte en C y C ++ se define para tener el tamaño de char, por lo que un byte en C tampoco siempre es exactamente de 8 bits.

Otra diferencia es que en C, un carácter sin signo no debe tener bits de relleno. Es decir, si encuentra que CHAR_BIT es 8, los valores de un personaje sin signo deben oscilar entre 0 .. 2 ^ CHAR_BIT-1. Lo mismo es cierto para char si no está firmado. Para el carácter firmado, no puede asumir nada sobre el rango de valores, incluso si sabe cómo su compilador implementa el material de signo (complemento de dos u otras opciones), puede haber bits de relleno no utilizados en él. En C ++, no hay bits de relleno para los tres tipos de caracteres.

  
    

" ¿Qué significa que se firme un carácter? "

  

Tradicionalmente, el conjunto de caracteres ASCII consta de codificaciones de caracteres de 7 bits. (A diferencia del EBCIDIC de 8 bits).

Cuando el lenguaje C fue diseñado e implementado, este fue un problema importante. (Por varias razones, como la transmisión de datos a través de dispositivos de módem en serie). El bit adicional tiene usos como la paridad.

A " carácter con signo " resulta ser perfecto para esta representación.

Los datos binarios, OTOH, simplemente toman el valor de cada 8! " chunk " de datos, por lo tanto, no se necesita ningún signo.

La aritmética en bytes es importante para los gráficos de computadora (donde los valores de 8 bits a menudo se usan para almacenar colores). Aparte de eso, puedo pensar en dos casos principales en los que el signo de char es importante:

  • convirtiendo a un int más grande
  • funciones de comparación

Lo desagradable es que no te morderán si todos tus datos de cadena son de 7 bits. Sin embargo, promete ser una fuente interminable de errores oscuros si está intentando que su programa C / C ++ sea de 8 bits limpio.

La firma funciona prácticamente de la misma manera en chars como ocurre en otros tipos integrales.Como habrás notado, los caracteres son en realidad solo números enteros de un byte.(No necesariamente de 8 bits, ¡aunque!Hay una diferencia;un byte puede ser mayor que 8 bits en algunas plataformas, y charLos s están bastante ligados a bytes debido a las definiciones de char y sizeof(char).El CHAR_BIT macro, definida en <limits.h> o C++ <climits>, le dirá cuántos bits hay en un char.).

En cuanto a por qué querrías un personaje con un letrero:en C y C++, no existe un tipo estándar llamado byte.Para el compilador, charLos s son bytes y viceversa, y no distingue entre ellos.A veces, sin embargo, quieres... a veces desear eso char ser un número de un byte, y en esos casos (particularmente qué tan pequeño puede ser el rango de un byte), normalmente también le importa si el número está firmado o no.Personalmente he usado la firma (o la falta de firma) para decir que un determinado char es un "byte" (numérico) en lugar de un carácter, y que se utilizará numéricamente.Sin una firma especificada, eso char realmente es un carácter y está destinado a ser utilizado como texto.

Más bien solía hacer eso.Ahora las versiones más nuevas de C y C++ tienen (u?)int_least8_t (actualmente escrito en <stdint.h> o <cstdint>), que son más explícitamente numéricos (aunque normalmente serán solo definiciones tipográficas para firmadas y no firmadas). char tipos de todos modos).

La única situación en la que puedo imaginar que esto es un problema es si eliges hacer matemáticas en los caracteres. Es perfectamente legal escribir el siguiente código.

char a = (char)42;
char b = (char)120;
char c = a + b;

Dependiendo de la firma del carácter, c podría ser uno de los dos valores. Si los caracteres no están firmados, entonces c será (carácter) 162. Si están firmados, será un caso de desbordamiento ya que el valor máximo para un carácter firmado es 128. Supongo que la mayoría de las implementaciones simplemente devolverían (char) -32.

Una cosa sobre los caracteres firmados es que puede probar c > = '' (espacio) y asegurarse de que sea un carácter ascii imprimible normal. Por supuesto, no es portátil, por lo que no es muy útil.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top