代码示例:1.2.3 运算符与优先级
全部示例均标注编译命令、适用环境与实测状态;完整验证记录见《03.5-代码编译运行验证记录》。
examples/ex1-bit-macros.c · 四个位操作宏(SET/CLEAR/TOGGLE/IS_SET)
/* ex1-bit-macros.c —— 四个位操作宏(1.2.3) * 适用环境:Linux / Windows(MinGW) 标准:C11(纯标准,无 GNU 扩展) * 编译:gcc ex1-bit-macros.c -o ex1 -std=c11 -Wall -Wextra -Wpedantic * 运行:./ex1(Windows: ex1.exe) * 说明:宏参数与整体都加括号;用 1u(unsigned)而非 1,避免 int 符号位左移的 UB。 */ #include <stdio.h> #define SET_BIT(reg, n) ((reg) | (1u << (n))) #define CLEAR_BIT(reg, n) ((reg) & ~(1u << (n))) #define TOGGLE_BIT(reg, n) ((reg) ^ (1u << (n))) #define IS_SET(reg, n) (((reg) >> (n)) & 1u) int main(void) { unsigned int reg = 0; reg = SET_BIT(reg, 3); /* 0b1000 = 8 */ printf("SET_BIT(0,3) = 0x%X\n", reg); reg = SET_BIT(reg, 0); /* 8 | 1 = 9 */ printf("再 SET_BIT(8,0) = 0x%X\n", reg); reg = CLEAR_BIT(reg, 3); /* 9 & ~8 = 1 */ printf("CLEAR_BIT(9,3) = 0x%X\n", reg); reg = TOGGLE_BIT(reg, 7); /* 1 ^ 128 = 129 (0x81) */ printf("TOGGLE_BIT(1,7) = 0x%X\n", reg); printf("IS_SET(0x81,7) = %u\n", IS_SET(reg, 7)); printf("IS_SET(0x81,3) = %u\n", IS_SET(reg, 3)); return 0; }examples/ex2-precedence.c · 优先级/结合性/短路/三目/逗号演示
/* ex2-precedence.c —— 优先级/结合性/短路/三目/逗号(1.2.3) * 适用环境:Linux / Windows(MinGW) 标准:C11(纯标准,无 GNU 扩展) * 编译:gcc ex2-precedence.c -o ex2 -std=c11 -Wall -Wextra -Wpedantic * 运行:./ex2(Windows: ex2.exe) */ #include <stdio.h> static int one(void) { printf("调用 one\n"); return 1; } static int zero(void) { printf("调用 zero\n"); return 0; } int main(void) { int a = 2, b = 3, c = 4; int x, y; x = a + b * c; /* 2 + 12 = 14:* 高于 + */ printf("a + b * c = %d(* 高于 +)\n", x); x = (a + b) * c; /* 5 * 4 = 20:括号改变结合 */ printf("(a + b) * c = %d(括号改变结合)\n", x); a = b = c; /* 赋值右结合:从右向左,a=b=4 */ printf("a = b = c 之后: a=%d b=%d c=%d\n", a, b, c); x = 5 < 3 && one(); /* 短路:左边为假,one() 不调用 */ printf("5 < 3 && one() = %d(one 未被调用)\n", x); y = 1 || zero(); /* 短路:左边为真,zero() 不调用 */ printf("1 || zero() = %d(zero 未被调用)\n", y); x = (a > b) ? 100 : 200; /* 三目:a=4,b=4 → 假 → 200 */ printf("(a > b) ? 100 : 200 = %d\n", x); x = (a = 1, b = 2, a + b); /* 逗号表达式:依次求值,取最右 a+b */ printf("(a=1, b=2, a+b) = %d(逗号表达式取最右值)\n", x); printf("sizeof(int) = %zu(sizeof 是运算符不是函数)\n", sizeof(int)); return 0; }examples/ex3-ub-static.txt · UB 与求值顺序辨析(conceptual:静态讲解,不运行)
# 1.2.3 未定义行为与求值顺序(conceptual 静态讲解——仅讲解,不运行) ## 一、未定义行为(UB):不要写,也不要试图预测输出 \`\`\`c int i = 1; int r = i++ + i++; /* UB:同一表达式内多次修改同一变量且中间无序列点 */ int r2 = ++i * ++i; /* UB:同理 */ \`\`\` - 标准(C11 §6.5p2)说"标准不保证任何结果"——编译器有权生成任意行为; - 某次运行恰好"对了"不代表代码正确;换编译器/优化级别结果可能不同; - 正确做法:拆成多行,一个表达式内同一变量最多修改一次。 ## 二、未指定顺序(合法,但顺序不保证) \`\`\`c int r3 = f() + g() * h(); /* 合法。f/g/h 的调用先后顺序未指定 */ \`\`\` - 优先级只决定结构(先算 g()*h() 再与 f() 相加),不决定 f/g/h 谁先被调用; - 如果 f/g/h 有副作用且互相影响,结果依赖实现——顺序敏感必须拆行。 ## 三、保证求值顺序的少数运算符(C11) - \`&&\`、\`||\`:短路,先左后右,右边可能不求值; - \`?:\`:只求值被选中的分支; - 逗号 \`,\`:从左到右依次求值。 ## 四、一句话纪律 > 一个表达式里,同一变量最多修改一次;需要顺序就拆行;拿不准就加括号。 (本示例按 C11 标准 N1570 §6.5p2、§6.5.2.2p10、§6.5.13/6.5.14/6.5.15/6.5.17 核对,未运行——运行 UB 代码没有意义。)