非常教程

C参考手册

C 语法

Undefined behavior

C语言标准精确地规定了C语言程序的可观察行为,除了以下几类:

  • 未定义的行为 - 对程序的行为没有限制。未定义行为的例子是数组边界之外的内存访问,有符号整数溢出,空指针取消引用,在没有序列点的表达式中多次修改相同标量,通过不同类型的指针访问对象等。编译器不需要诊断未定义的行为(虽然诊断了许多简单情况),编译后的程序不需要做任何有意义的事情。
  • 未指定的行为 - 允许两个或更多行为,并且不需要实现来记录每个行为的影响。例如,评估顺序,相同的字符串文字是否不同等。每个未指定的行为都会导致一组有效结果中的一个,并且在同一程序中重复时可能会产生不同的结果。
  • 实现定义的行为 - 未指定的行为,其中每个实现记录如何进行选择。例如,一个字节中的位数,或者有符号整数右移是算术还是逻辑。
  • 特定于语言环境的行为 - 实现定义的行为取决于当前选择的语言环境。例如,对于islower除26个小写拉丁字母以外的任何字符,是否返回true。

(注意:严格符合的程序不依赖于任何未指定的,未定义的或实现定义的行为)。

编译器需要为任何违反C语法规则或语义约束的程序发布诊断消息(错误或警告),即使其行为被指定为未定义或实现定义的,或者编译器提供了允许它的语言扩展接受这样的计划。对未定义行为的诊断不是必需的。

UB和优化

由于正确的C程序没有未定义的行为,因此编译器可能会在实际具有UB的程序在启用优化的情况下编译时产生意外的结果:

例如,

签名溢出

int foo(int x) {
    return x+1 > x; // either true or UB due to signed overflow
}

可能被编译为(演示)。

foo(int):
        movl    $1, %eax
        ret

访问出界

int table[4] = {};
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;
}

可以编译为(演示)。

exists_in_table(int):
        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");

可能产生以下输出(用旧版本的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; 
}

可以编译为(演示)。

f(int):
        mov     eax, 42
        ret

访问传递给realloc的指针

选择clang以观察显示的输出。

#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);
}

可能的输出:

12

无限循环无副作用

选择clang以观察显示的输出。

#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.");
}

可能的输出:

Fermat's Last Theorem has been disproved.

参考

  • C11标准(ISO / IEC 9899:2011):
    • 3.4行为(p:3-4)
    • 4/2未定义的行为(p:8)
  • C99标准(ISO / IEC 9899:1999):
    • 3.4行为(p:3-4)
    • 4/2未定义的行为(p:7)
  • C89 / C90标准(ISO / IEC 9899:1990):
    • 1.6术语定义

C 语法相关

1.#define directive
2.#elif directive
3.#else directive
4.#endif directive
5.#error directive
6.#if directive
7.#ifdef directive
8.#ifndef directive
9.#include directive
10.#line directive
11.#pragma directive
12.alignas
13.Alternative operators and tokens
14.Analyzability
15.Arithmetic operators
16.Arithmetic types
17.Array declaration
18.Array initialization
19.ASCII Chart
20.Assignment operators
21. types
22.Basic concepts
23.Bit fields
24.break statement
25.C language
26.C Operator Precedence
27.cast operator
28.character constant
29.Comments
30.Comparison operators
31.compound literals
32.Conditional inclusion
33.Conformance
34.const type qualifier
35.Constant expressions
36.continue statement
37.Declarations
38.do-while loop
39.Enumerations
40.Escape sequences
41.Expressions
42.External and tentative definitions
43.File scope
44.floating constant
45.for loop
46.Function declarations
47.Function definitions
48.Functions
49.Generic selection
50.goto statement
51.Identifier
52.if statement
53.Implicit conversions
54.Increment/decrement operators
55.Initialization
56.inline function specifier
57.integer constant
58.Lifetime
59.Logical operators
60.Lookup and name spaces
61.Main function
62.Member access operators
63.Memory model
64.Objects and alignment
65.Order of evaluation
66.Other operators
67.Phases of translation
68.Pointer declaration
69.Preprocessor
70.restrict type qualifier
71.return statement
72.Scalar initialization
73.Scope
74.sizeof operator
75.Statements
76.static assert declaration
77.Static storage duration
78.Storage-class specifiers
79.string literals
80.Struct and union initialization
81.Struct declaration
82.switch statement
83.Thread storage duration
84.Type
85.Type
86.Typedef declaration
87.Union declaration
88.Value categories
89.Variadic arguments
90.volatile type qualifier
91.while loop
92._Alignof operator
93._Noreturn function specifier
C

C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。