The C language standard precisely specifies the observable behavior of C language programs, except for the ones in the following categories:
islower
returns true for any character other than the 26 lowercase Latin letters. (Note: Strictly conforming programs do not depend on any unspecified, undefined, or implementation-defined behavior).
The compilers are required to issue diagnostic messages (either errors or warnings) for any programs that violates any C syntax rule or semantic constraint, even if its behavior is specified as undefined or implementation-defined or if the compiler provides a language extension that allows it to accept such program. Diagnostics for undefined behavior are not otherwise required.
Because correct C programs are free of undefined behavior, compilers may produce unexpected results when a program that actually has UB is compiled with optimization enabled:
For example,
int foo(int x) { return x+1 > x; // either true or UB due to signed overflow }
may be compiled as (demo).
foo: movl $1, %eax ret
int table[4] = {0}; int exists_in_table(int v) { // return true in one of the first 4 iterations or UB due to out-of-bounds access for (int i = 0; i <= 4; i++) { if (table[i] == v) return 1; } return 0; }
May be compiled as (demo).
exists_in_table: movl $1, %eax ret
_Bool p; // uninitialized local variable if(p) // UB access to uninitialized scalar puts("p is true"); if(!p) // UB access to uninitialized scalar puts("p is false");
May produce the following output (observed with an older version of gcc):
p is true p is false
size_t f(int x) { size_t a; if(x) // either x nonzero or UB a = 42; return a; }
May be compiled as (demo).
f: mov eax, 42 ret
int f(void) { _Bool b = 0; unsigned char* p =(unsigned char*)&b; *p = 10; // reading from b is now UB return b == 0; }
May be compiled as (demo).
f(): movl $11, %eax ret
int foo(int* p) { int x = *p; if(!p) return x; // Either UB above or this branch is never taken else return 0; } int bar() { int* p = NULL; return *p; // Unconditional UB }
may be compiled as (foo with gcc, bar with clang).
foo: xorl %eax, %eax ret bar: retq
Choose clang to observe the output shown.
#include <stdio.h> #include <stdlib.h> int main(void) { int *p = (int*)malloc(sizeof(int)); int *q = (int*)realloc(p, sizeof(int)); *p = 1; // UB access to a pointer that was passed to realloc *q = 2; if (p == q) // UB access to a pointer that was passed to realloc printf("%d%d\n", *p, *q); }
Possible output:
12
Choose clang to observe the output shown.
#include <stdio.h> int fermat() { const int MAX = 1000; int a=1,b=1,c=1; // Endless loop with no side effects is UB while (1) { if (((a*a*a) == ((b*b*b)+(c*c*c)))) return 1; a++; if (a>MAX) { a=1; b++; } if (b>MAX) { b=1; c++; } if (c>MAX) { c=1;} } return 0; } int main(void) { if (fermat()) puts("Fermat's Last Theorem has been disproved."); else puts("Fermat's Last Theorem has not been disproved."); }
Possible output:
Fermat's Last Theorem has been disproved.
C++ documentation for Undefined behavior |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/behavior