2012-09-19 18 views
7

me escribió el siguiente código C:C constante hexadecimal tipo

#include <stdio.h> 

int main() { 
    printf("%d\n", -1 >> 8); 
    return 0; 
} 

puedo compilar el código con gcc 4.6.3 en mi x86_64 usando la bandera -m32. Obtengo -1 impreso como esperaría, el cambio ocurre aritméticamente usando la representación de complemento de dos que resulta en -1.

Ahora bien, si en lugar de escribir

printf("%d\n", 0xFFFFFFFF >> 8); 

consigo 16777215. lo que habría esperado esta constante debe ser interpretado como un int (firmado) y luego el turno de ser la aritmética que daría lugar a -1 de nuevo. He revisado el último estándar C y parece que no puedo entender por qué este es el caso. ¿Algunas ideas?

+0

Es la diferencia entre signed (-1) y unsigned (0xFFFFFFFF) – SpacedMonkey

+0

@SpacedMonkey Estoy preguntando por qué 0xFFFFFFFF no tiene firma – dschatz

+0

@SpacedMonkey Btw, '-' no contribuye a esta diferencia. '-' sigue siendo un operador unario y no hace que algo se firme. Es '1' que está firmado (y por lo tanto' -1' también está firmado), mientras que '0xFFFFFFFF' no está firmado. –

Respuesta

10

Según el estándar C99 (6.4.4.1), las constantes hexadecimales será el primer tipo en esta lista que puede representar ellos:

int 
unsigned int 
long int 
unsigned long int 
long long int 
unsigned long long int 

El hex literal 0xFFFFFFFF no cabe en un int (que puede mantenga los valores -0x80000000 en 0x7FFFFFFF), pero cabe en unsigned int, y por lo tanto su tipo no será firmado. Desplazar a la derecha el valor sin signo 0xFFFFFFFF por 8 da 16777215.

+0

¿Por qué 0xFFFFFFFF no encaja en un int? – dschatz

+0

@dschatz: Porque es 4294967295, y su 'int' solo puede ir hasta 2147483647. –

+0

@dschatz: Acabo de editar para agregar - Porque es más que 0x7fffffff que es el valor más grande representable por un int de 32 bits usando el complemento de 2 representación. – interjay

10

literales integrales sin decoración tienen diferente tipo dependiendo de si son o no decimal (6.4.4.1/5 en C11, Tabla 6 en C++ 11):

  • literales decimales, es decir [1-9][0-9]*, son siempre firmado.

  • literales hexadecimales y octales están firmados o no. Si el valor es demasiado grande para un tipo con signo, pero lo suficientemente pequeño para ajustarse al tipo sin signo del mismo ancho, no estará firmado. (Esto es lo que sucede a su constante hexadecimal.)

derecho de cambio de números enteros negativos es definido por la implementación, y que sucede conseguir la extensión con signo. Desplazar a la derecha el valor sin signo es simple división por dos.

+0

El borrador estándar C que encontré aquí http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf muestra que las constantes hexadecimales son entradas antes de las entradas sin signo en la página 64. ¿Qué es lo que me falta? ? – dschatz

+1

Lo que usted dice no coincide con el estándar C99 (6.4.4.1/5). Según ese decimal, las constantes están firmadas y las hexadecimal/octal pueden estar firmadas o no. – interjay

+1

@dschatz: Oh, lo hice al revés. Déjame arreglarlo! De hecho, es lo mismo en C++ y C. –