Warum ist dies ein undefiniertes Verhalten?

Warum ist dies ein undefiniertes Verhalten?


Meine Antwort auf diese Frage war diese Funktion:


inline bool divisible15(unsigned int x) 
{
//286331153 = (2^32 - 1) / 15
//4008636143 = (2^32) - 286331153
return x * 4008636143 <= 286331153;
}

Es hat auf meiner Maschine mit dem VS2008-Compiler perfekt funktioniert, aber hier funktioniert es überhaupt nicht.


Hat jemand eine Idee, warum ich auf verschiedenen Compilern unterschiedliche Ergebnisse erhalte? unsigned Überlauf ist kein undefiniertes Verhalten.


Wichtiger Hinweis: Nach einigen Tests wurde bestätigt, dass es schneller ist, als den Rest der Division durch 15 zu nehmen. (Allerdings nicht bei allen Compilern)


Antworten:


Es ist kein undefiniertes Verhalten, es ist nur eine bahnbrechende Änderung im C-Sprachstandard zwischen C89 und C99.


In C89 ganzzahlige Konstanten wie 4008636143, die nicht in eine int passen oder long int aber passen in einen unsigned int sind unsigniert, aber in C99 sind sie entweder long int oder long long int (je nachdem, welcher der kleinste ist, der den Wert halten kann). Als Ergebnis werden alle Ausdrücke mit 64 Bit ausgewertet, was zu einer falschen Antwort führt.


Visual Studio ist ein C89-Compiler und führt daher zum C89-Verhalten, aber dieser Ideone-Link kompiliert im C99-Modus.


Dies wird deutlicher, wenn Sie mit GCC mit -Wall kompilieren :


test.c: In function ‘divisible15’:
test.c:8:3: warning: this decimal constant is unsigned only in ISO C90

Aus C89 §3.1.3.2:



C99 §6.4.4.1/5-6:



Der Vollständigkeit halber hat C++03 tatsächlich ein undefiniertes Verhalten, wenn die Integer-Konstante zu groß ist, um in einen long int zu passen . Aus C++03 §2.13.1/2:



Das C++11-Verhalten ist identisch mit C99, siehe C++11 §2.14.2/3.


Um sicherzustellen, dass sich der Code konsistent verhält, wenn er entweder als C89, C99, C++03 oder C++11 kompiliert wird, besteht die einfache Lösung darin, die Konstante 4008636143 unsigniert zu machen, indem ihr das Suffix u hinzugefügt wird als 4008636143u .


Einige Code-Antworten


int val = 5;
return val / 0;
// undefined behavior
int arr[4] = {0, 1, 2, 3};
return arr[5];
// undefined behavior for indexing out of bounds
int x = INT_MAX;
printf("%d", x + 1);
// undefined behavior
val = 0;
int ptr = *val;
// undefined behavior for dereferencing a null pointer
char* s = "geeksforgeeks";
s[0] = 'e';
// undefined behavior
int* ptr =NULL;
printf("%d", *ptr);
// undefiniertes Verhalten für den Zugriff auf den NULL-Zeiger
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72