2010-05-05 7 views
10

Varias preguntas en este sitio web revelan dificultades al mezclar tipos firmados y no firmados y la mayoría de los compiladores parecen hacer un buen trabajo al generar advertencias de este tipo. Sin embargo, a GCC no parece importarle asignar una constante con signo a un tipo sin signo. Considere el siguiente programa:¿Por qué GCC no produce una advertencia al asignar un literal firmado a un tipo sin firmar?

/* foo.c */ 
#include <stdio.h> 
int main(void) 
{ 
    unsigned int x=20, y=-30; 
    if (x > y) { 
     printf("%d > %d\n", x, y); 
    } else { 
     printf("%d <= %d\n", x, y); 
    } 
    return 0; 
} 

compilación con GCC 4.2.1 que a continuación no produce ninguna salida en la consola:

gcc -Werror -Wall -Wextra -pedantic foo.c -o foo 

El ejecutable resultante genera el siguiente resultado:

$ ./foo 
20 <= -30 

Es Hay alguna razón por la que GCC no genera ningún mensaje de advertencia o error al asignar el valor con signo -30 a la variable entera sin signo y?

+3

Tenga en cuenta que debe usar% u para imprimir 'unsigned int'. –

+0

@Bastien, de hecho; tal vez lo más interesante es que, como señaló AndreyT en su respuesta a continuación, 'printf ("% d ")' muestra el valor firmado en lugar del valor sin signo (4294967266) que utiliza el operador de comparación. – maerics

+1

Se debe a la representación del complemento a 2 de int firmado: http://en.wikipedia.org/wiki/Two%27s_complement (esta representación no está garantizada por el estándar C, pero en la práctica nunca he oído hablar de otra representación todavía está en uso) –

Respuesta

14

Uso -Wconversion:

~/src> gcc -Wconversion -Werror -Wall -Wextra -pedantic -o signwarn signwarn.c 
cc1: warnings being treated as errors 
signwarn.c: In function 'main': 
signwarn.c:5: error: negative integer implicitly converted to unsigned type 

supongo que la cosa aquí es que gcc es realmente muy bueno en la generación de avisos, pero el valor predeterminado es no hacerlo en los casos (a veces inesperadas). Es una buena idea navegar a través de las advertencias disponibles y elegir un conjunto de opciones que generen las que considere útiles. ¡O solo a todos, y pulir ese código hasta que brille! :)

6

La capacidad de convertir el valor negativo al tipo sin firmar es una característica del lenguaje C. Por esta razón, la advertencia no se emite por defecto. Tienes que solicitarlo explícitamente, si así lo deseas.

En cuanto a lo que sus productos de los programas ... Usando %d especificador de formato de printf con un valor sin signo que se encuentra fuera del alcance de tipo int resulta en un comportamiento indefinido, que es lo que realmente observado en el experimento.

+0

Oye, buena captura. 'printf ("% d ", y);' está en una categoría completamente distinta de 'y = -30;'. –

+0

Gran punto, podría imaginar el uso de un valor negativo para crear un campo de bits deseado, por ejemplo. – maerics

+1

Sí, la conversión de # negativos a unsigned se define para producir un 'módulo' de resultado del tamaño del int sin signo, por lo que (unsigned) -1 es una manera perfectamente buena de decir "unsigned with all 1s in it". Cuando los números con signo están representados con el complemento de 2, esta "conversión" es simplemente el mismo patrón de bits que el firmado. – greggo

1

El uso de (sin signo) -1 es una forma utilizada a menudo para establecer todos los bits e incluso se cita como motivo de esta (mis) característica de C, incluso por personas que deberían saber mejor . No es ni obvio ni portátil: la expresión que desea usar para configurar todos los bits es ~ 0.

+0

considero el significado de "uint32_t x = -1;' obvio, la norma especifica el comportamiento preciso, y es más portátil que sería 'uint32_t x = ~ 0; 'o' uint32_t x = ~ 0U; '[en una sistema de magnitud de signo, el formulario '~ 0' establecería' x' en 0xFFFF8001ul; en cualquier sistema de 16 bits, el formulario '~ 0u' establecería' x' en 0x0000FFFFul; el formulario que utiliza '-1' funcionará en cualquier sistema que define 'uint32_t'.] – supercat

Cuestiones relacionadas