sintaxis data array c language-lawyer undefined-behavior bit-shift

data - Es 1<< 31 bien definido en C cuando sizeof(int)== 4



unsigned short en c (3)

Invoca un comportamiento indefinido, como se explica en las otras respuestas / comentarios. Sin embargo, en cuanto a por qué GCC no emite un diagnóstico.

En realidad, hay dos cosas que pueden llevar a un comportamiento indefinido para un desplazamiento a la izquierda (ambos de [6.5.7] ):

  1. Si el valor del operando derecho es negativo o es mayor o igual que el ancho del operando izquierdo promovido, el comportamiento no está definido.

  2. Si E1 tiene un tipo con signo y un valor no negativo, y E1 × 2 E2 es representable en el tipo de resultado, ese es el valor resultante; de lo contrario, el comportamiento es indefinido.

Evidentemente, GCC detecta el primero (porque es trivial hacerlo), pero no el último.

Según la respuesta a estas preguntas :

El resultado de E1 << E2 es E1 posiciones de bit E2 desplazadas a la izquierda; bits vacíos están llenos de ceros. Si E1 tiene un tipo sin signo, el valor del resultado es E1 × 2 E2 , módulo reducido uno más que el valor máximo representable en el tipo de resultado. Si E1 tiene un tipo con signo y un valor no negativo, y E1 × 2 E2 es representable en el tipo de resultado, ese es el valor resultante; de lo contrario, el comportamiento no está definido.

Lo que parece implicar que 1 << 31 no está definido.

Sin embargo, GCC no emite una advertencia si uso 1 << 31 . Se emite uno por 1 << 32 . enlazar

Entonces, ¿cuál es? ¿Estoy entendiendo mal el estándar? ¿Tiene GCC su propia interpretación?


La razón por la que GCC no advierte sobre esto es porque 1 << 31 era válido (pero definido por la implementación) en C90, y es válido (pero definido por la implementación) incluso en C ++ moderno. C90 define << como un cambio de bit y le sigue diciendo que para los tipos sin signo, su resultado fue el de una multiplicación, pero no hizo tal cosa para los tipos con signo, lo que implícitamente lo hizo válido y lo dejó cubierto por la redacción general que los operadores bitwise Tener aspectos definidos por implementación para tipos firmados. C ++ hoy en día define << como multiplicar al tipo sin signo correspondiente, con el resultado convertido de nuevo al tipo firmado, que también está definido por la implementación.

C99 y C11 hicieron esto inválido (diciendo que el comportamiento no está definido), pero los compiladores pueden aceptarlo como una extensión. Para compatibilidad con el código existente y para compartir código entre las -fsanitize=undefined C y C ++, GCC continúa haciéndolo, con una excepción: puede usar -fsanitize=undefined para obtener un comportamiento no definido detectado para abortar su programa en tiempo de ejecución, y esto uno maneja 1 << 31 , pero solo cuando compila como C99 o C11.


No: 1 << 31 tiene un comportamiento indefinido si el tipo int tiene solo 31 bits de valor.

1U << 31 está bien y se evalúa como 0x80000000 si el tipo unsigned int tiene 32 bits de valor.

En un sistema donde los bytes tienen 8 bits, sizeof(int) == 4 significa que int tiene como máximo 31 bits de valor, por lo que desplazar 1 por 31 lugares no está definido. A la inversa, en un sistema donde CHAR_BIT > 8 , puede estar bien escribir 1 << 31 .

gcc podría emitir una advertencia si elevas el nivel de advertencia. prueba gcc -Wall -Wextra -W -Werror . clang emite una advertencia con las mismas opciones.

Para abordar los comentarios de Michaël Roy, 1 << 31 no evalúa a INT_MIN manera confiable. Puede dar este valor a su sistema, pero el Estándar no lo garantiza, de hecho, el Estándar lo describe como un comportamiento indefinido, por lo que no solo no puede confiar en él, sino que también debe evitarlo para evitar errores falsos. Los optimizadores rutinariamente aprovechan el potencial comportamiento indefinido para eliminar el código y romper las suposiciones de los programadores.

Por ejemplo, el siguiente código podría compilar en un return 1; simple return 1; :

int check_shift(int i) { if ((1 << i) > 0) return 1; else return 0; }

Ninguno de los compiladores soportados por el explorador del compilador de Godbolt lo hace, pero hacerlo no rompería la conformidad.