C语言操作符全解析 C语言操作符详解

C语言操作符全解析(详解 + 优先级表 + 常见陷阱)

C语言的操作符是表达式求值的基础。理解优先级结合性副作用是写出正确、高效代码的关键。C23标准(2024正式发布)对操作符本身改动很小,主要新增了 typeoftypeof_unqual 等关键字,但核心操作符表保持稳定。

1. 操作符优先级与结合性完整表(C23)

优先级从高到低(数字越小优先级越高),同一行的运算符优先级相同。

优先级操作符描述结合性备注
1() [] -> . ++ -- (后缀)函数调用、数组下标、指针成员、结构体成员、后缀自增自减左→右后缀最高
2++ -- (前缀) + - ! ~ * & (类型) sizeof _Alignof前缀自增自减、一元正负、逻辑非、按位取反、解引用、取地址、强制转换、sizeof、对齐右→左一元运算符
3* / %乘、除、取模左→右
4+ -加、减左→右二元
5<< >>左移、右移左→右
6< <= > >=小于、小于等于、大于、大于等于左→右关系
7== !=等于、不等于左→右相等
8&按位与左→右
9^按位异或左→右
10|按位或左→右
11&&逻辑与左→右短路求值
12||逻辑或左→右短路求值
13?:条件(三元)运算符右→左
14= += -= *= /= %= &= ^= |= <<= >>=赋值及复合赋值右→左
15,逗号运算符左→右最低

记忆技巧

  • 后缀 > 一元 > 算术 > 移位 > 关系 > 相等 > 位运算 > 逻辑 > 条件 > 赋值 > 逗号
  • 不确定时永远加括号,这是防御性编程的最佳实践。

2. 各类操作符详解

2.1 算术操作符

  • + - * / %
  • /% 对整数是整数除法(向零截断)。
  • % 要求操作数为整数。

自增自减(++ –)重点

  • 前缀++i):先修改后使用
  • 后缀i++):先使用后修改
int i = 5;
int a = ++i;   // a=6, i=6
int b = i++;   // b=6, i=7

陷阱a = i++ + ++i; → 未定义行为(UB),不要在同一个表达式中多次修改同一变量。

2.2 关系与相等操作符

  • < <= > >= == !=
  • 结果为 int 类型:真为1,假为0。
  • 常见陷阱if (a = 5)(赋值)而不是 if (a == 5)(比较)——这是经典Bug。

2.3 逻辑操作符(&& || !)

  • &&||短路求值特性:
  • a && b:a为假时不求值b
  • a || b:a为真时不求值b

示例(安全写法):

if (ptr != NULL && ptr->data > 0)  // 防止野指针

2.4 位操作符(最重要之一)

  • &(与)、|(或)、^(异或)、~(取反)
  • <<(左移)、>>(右移)

经典用途

// 设置第n位
flags |= (1U << n);
// 清除第n位
flags &= ~(1U << n);
// 判断第n位是否为1
if (flags & (1U << n))
// 取反
flags ^= (1U << n);

// 右移负数注意:算术右移(符号位扩展)还是逻辑右移(实现定义,建议用无符号类型)
unsigned int u = 0xFFFFFFFFU;
u >>= 1;   // 安全

陷阱a & b == 0 实际是 a & (b == 0),因为 == 优先级高于 &。正确写法:(a & b) == 0

2.5 赋值操作符

  • 简单赋值 =
  • 复合赋值 += -= *= /= %= &= |= ^= <<= >>=

结合性为右→左

a = b = c = 0;   // 等价于 a = (b = (c = 0));

2.6 条件运算符(三元)

max = (a > b) ? a : b;

陷阱:三元运算符优先级较低,容易出错时加括号。

2.7 逗号运算符

i = (j=3, j+2);   // 先执行j=3,再j+2,最后i=5

常用于 for 循环或宏定义中。

2.8 sizeof 与类型转换

  • sizeof 返回 size_t(无符号),操作数可以是类型或表达式。
  • (类型)表达式:强制转换(可能丢失精度或引发未定义行为)。

C23 新增:

  • typeof(expr)typeof_unqual(expr):获取类型(类似C++ decltype)。

2.9 指针与成员操作符

  • &(取地址)、*(解引用)
  • .(结构体成员)、->(指针成员)

经典陷阱

*p++   // 等价于 *(p++),不是 (*p)++

3. 常见陷阱与防御性编程

  1. 优先级错误a & b == cif (x & 1 == 0)
  2. = vs ==:编译器通常会警告 if (x = 5)
  3. 位运算与逻辑运算混淆& vs &&| vs ||
  4. 自增/自减副作用:同一变量多次出现
  5. 短路求值依赖:不要把有副作用的表达式放在 &&/|| 右侧
  6. 移位超过位宽1 << 32 在32位int上是未定义行为
  7. 有符号右移:负数右移可能保留符号位

最佳实践

  • 复杂表达式必须加括号
  • 使用 unsigned 类型处理位运算
  • 开启编译器警告(-Wall -Wextra
  • 代码审查时重点检查优先级相关表达式

总结

C语言操作符设计精巧但优先级复杂,“多用括号,少靠记忆” 是最可靠的策略。熟练掌握位运算和短路求值,能大幅提升代码性能和简洁度。

如果你想深入某个部分(例如位运算实战、sizeof 底层原理、C23 typeof 使用示例、常见面试题解析等),或者需要完整优先级记忆口诀、练习题,请告诉我,我可以继续展开!

文章已创建 4631

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部