c/language/behavior

The C language standard precisely specifies the of C language programs, except for the ones in the following categories:


 * undefined behavior - there are no restrictions on the behavior of the program. Examples of undefined behavior are memory accesses outside of array bounds, signed integer overflow, null pointer dereference, modification of the same scalar in an expression without sequence points, access to an object through a pointer of a different type, etc. Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful.


 * unspecified behavior - two or more behaviors are permitted and the implementation is not required to document the effects of each behavior. For example,, whether identical s are distinct, etc. Each unspecified behavior results in one of a set of valid results and may produce a different result when repeated in the same program.


 * implementation-defined behavior - unspecified behavior where each implementation documents how the choice is made. For example, number of bits in a byte, or whether signed integer right shift is arithmetic or logical.


 * locale-specific behavior - implementation-defined behavior that depends on the currently chosen locale. For example, whether islower returns true for any character other than the 26 lowercase Latin letters.

(Note: 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.

UB and optimization
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,

Signed overflow
may be compiled as (demo)

Access out of bounds
May be compiled as (demo)

Uninitialized scalar
May produce the following output (observed with an older version of gcc):

May be compiled as (demo)

Invalid scalar
May be compiled as (demo)

Null pointer dereference
may be compiled as (foo with gcc, bar with clang)