c gcc overflow division modulo

¿INT_MIN%-1 produce un comportamiento indefinido?



gcc overflow (5)

gcc genera código flotante que genera SIGFPE para el siguiente código:

#include <limits.h> int x = -1; int main() { return INT_MIN % x; }

Sin embargo, no puedo encontrar ninguna declaración en el estándar de que este código invoque un comportamiento indefinido o definido por la implementación. Por lo que puedo decir, se requiere devolver 0. ¿Es esto un error en gcc o me falta alguna excepción especial que hace el estándar?


El resultado de la operación de módulo con operandos negativos se deja definido en la implementación en C89, y se define en C99 por §6.5.5 / 6:

... el resultado del operador / es el cociente algebraico con cualquier parte fraccional descartada. 88) Si el cociente a/b es representable, la expresión (a/b)*b + a%b será igual a .

88) Esto a menudo se llama "truncamiento hacia cero".

Para una representación de complemento de dos, INT_MIN / -1 es igual a INT_MAX + 1 , por lo que no es representable como un int sin envoltura, y supongo que la implementación elige dejarlo explosivo.




Probablemente tengas razón de que esto puede considerarse un error en el estándar real. El borrador actual aborda este problema:

Si el cociente a / b es representable, la expresión (a / b) * b + a% b será igual a; de lo contrario, el comportamiento de a / by a% b no está definido.


Observando el código ensamblador generado por gcc (x se define como -1 antes en el ensamblaje):

movl x, %ecx movl $-2147483648, %eax movl %eax, %edx sarl $31, %edx idivl %ecx

La primera instrucción computacional, sarl , desplaza a la derecha -2147483648 31 bits. Esto resulta en -1 que se pone en %edx .

Siguiente idivl se ejecuta. Esta es una operación firmada. Permítanme citar la descripción:

Divide el contenido de la doble palabra contenida en los registros combinados% edx:% eax por el valor en la ubicación de registro o memoria especificada.

Entonces -1:-2147483648 / -1 es la división que sucede. -1:-2147483648 interpretada como una palabra doble es igual a -2147483648 (en una máquina complementaria de dos). Ahora ocurre -2147483648 / -1 que devuelve 2147483648 . ¡AUGE! Esa es una más que INT_MAX .

Acerca de la pregunta ¿por qué? ¿Esto es un error en gcc o me falta alguna excepción especial que hace el estándar?

En el estándar C99 esto es UB implícito (§6.5.5 / 6):

... el resultado del operador / es el cociente algebraico con cualquier parte fraccional descartada.88) Si el cociente a / b es representable, la expresión (a / b) * b + a% b será igual a.

INT_MIN / -1 no se puede representar, por lo tanto, esto es UB.

En C89, sin embargo, el operador% está definido en la implementación y si se trata de un error del compilador o no se puede debatir. Sin embargo, el problema aparece en gcc: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30484