2010-10-22 10 views

Respuesta

6

ya su punto de partida es problemático:

char c = 0x80; 

Si (como al parecer en su caso) char es un tipo firmado, está asignando la constante entera 128 a un tipo que sólo está garantizado para contener valores de hasta a 127. Entonces su compilador puede elegir darle algún valor definido de implementación (-128 en su caso, supongo) o emitir un error de rango.

Luego está haciendo un cambio a la izquierda en ese valor negativo. Esto le da un comportamiento indefinido. En total tiene varias opciones de implementación definido más un comportamiento indefinido que determinan el resultado:

  • de signo de char
  • la elección de la forma de convertir 128 a signed char
  • el ancho de char
  • la representación signo de int (hay tres posibilidades)
  • la elección de cómo implementar (o no) el desplazamiento a la izquierda en negativo int

Puede ser un buen ejercicio para buscar todos estos casos y ver cuáles son los diferentes resultados.

En resumen algunas recomendaciones:

  • elige una constante apropiada para inicializar una variable
  • no hacen aritmética sencilla con char
  • No practico desplazamiento a la izquierda en los tipos firmados
+0

Gracias Jens señor por su respuesta. –

+0

El primer párrafo de la explicación es incorrecto y puede confundir a alguien sin experiencia. "char c = 0x80;" está bien al igual que "int c = 0xFFFFFFFF" está bien, pero la parte que no está bien es asumiendo que 0x80 será 128 cuando se pueda firmar char (rango de -128 a 127, no de 0 a 255) –

+0

@ B. Nadolson , No creo que sea engañoso. La constante '0x80' es de tipo' int' y tiene el valor '128'.Este tipo y valor en el RHS se determina primero, y luego ese tipo y valor se convierte para adaptarse al tipo en el LHS. Intentar inicializar una variable posiblemente firmada con un valor que no se ajusta al tipo es un error semántico. –

18

char pueden firmarse en su plataforma, en cuyo caso 0x80 representa -128 (suponiendo que hay dos complementos).

Cuando se usa char como operando con el operador <<, se promueve a int (todavía -128). Entonces, cuando aplicas el desplazamiento a la izquierda, obtienes -256. Técnicamente, el cambio de valores negativos es definido por la implementación indefinido, pero lo que se ve es un comportamiento típico.

+0

No creo que su declaración se refiera a la promoción 'int' es correcta. Los operadores de desplazamiento no hacen promoción, el tipo de resultado es el tipo de la izquierda. –

+0

@Jens: Para ser justos, solo tengo el estándar C99 frente a mí. Pero dice en la sección 6.5.7: "Las promociones enteras se realizan en cada uno de los operandos". –

+0

oops, a la derecha. Así que lo voy a integrar también en mi respuesta :) –

3

c tiene asignado 0x80. Suponiendo bytes de 8 bits, su valor en representación binaria es 10000000. Aparentemente, en su plataforma, char es un tipo firmado. Por lo tanto, 0x80 (es decir, 10000000) corresponde a -128.

Cuando << se aplica a un valor char, se promueve a int y se conserva el signo. Entonces, cuando se desplaza una vez hacia la izquierda, con enteros de 32 bits, se convierte en 11111111111111111111111100000000 (complemento de dos) que es -256.

+0

La promoción a 'int' no tiene nada que ver con' printf' en esta instancia; es debido al '<<'. Además, esa no es la representación de -256 en el complemento de uno o de dos. –

+0

@Oli Gracias por la corrección. –

+0

Muchas gracias Oli y Sinan. He entendido la lógica .. –

0

Me pregunto por qué su compilador no se queja con una advertencia de que 0x80 no cabe en char, que en su plataforma puede representar solo valores de -0x80 a 0x7F.

probar este pedazo de código:

#include <stdio.h> 
#include <limits.h> 
#include <stdlib.h> 

int main() { 
     printf("char can represent values from %d to %d.\n", CHAR_MIN, CHAR_MAX); 
     return EXIT_SUCCESS; 
} 

Su situación se denomina rebose.

1

Solo una nota al margen. Desde una perspectiva ascendente, el desplazamiento en bits (y el enmascaramiento) se basa en la longitud de palabra de una arquitectura (expresada en bits). La longitud de una palabra varía de una arquitectura a otra.

See this Wiki page for word lengths by architecture

Si se conoce la longitud de palabra de la arquitectura objetivo, se puede utilizar de desplazamiento de bits a multiplicar y dividir (en algunos casos), más rápido que el uso de operandos.

See this Wiki page for interesting diagrams of bit-shifting

Desde código poco desplazada es dependiente de la arquitectura, no se puede asumir una parte específica de código poco desplazada funcionará de la misma manera desde la arquitectura a la arquitectura. Sin embargo, una vez que uno está familiarizado con la idea de diferentes longitudes de palabra para diferentes arquitecturas, el cambio de bit se vuelve menos misterioso y más predecible.

Afortunadamente, hoy tenemos longitudes de palabra de 8, 16, 32 y 64 bits, y exclusivamente longitudes de caracteres de 8 bits. En los días de la informática antigua, una arquitectura podía tener una longitud de palabra de 12, 15 o 23 bits (etc., hasta el cansancio).

+0

Gracias Mike señor por compartir esta información. Todos ustedes tienen un gran conocimiento. –

Cuestiones relacionadas