运算符基础(上):算术、赋值与自增自减
各位同学,今天我们来聊聊C语言里最基础、也最常用的三类运算符。说实话,运算符这东西,你写每一行代码都离不开。我刚开始学C的时候,觉得不就是加减乘除嘛,有什么好讲的?结果后来在项目里踩了不少坑,才发现越是基础的东西,越容易出问题。
咱们今天就把算术运算符、赋值运算符、自增自减运算符这三兄弟彻底讲透。你想想看,如果连这些都不熟练,后面学指针、结构体的时候会更吃力。
核心要点:运算符的优先级、结合性、以及副作用,是嵌入式开发中容易出bug的三个重灾区。
一、算术运算符:不只是加减乘除
C语言里的算术运算符有五个:+、-、*、/、%。前四个大家都很熟悉,重点说说除法和取模。
1. 整数除法的陷阱
先看一段代码:
int a = 5;
int b = 2;
int c = a / b; // c 等于多少?
很多人脱口而出:2.5。但实际结果是 2。为什么?因为两个整数相除,结果还是整数,小数部分直接被截断了。这不是四舍五入,是直接丢掉小数部分。
注意:在嵌入式开发中,如果你需要精确的小数结果,一定要用浮点数。我曾经在一个电机控制项目里,用整数除法计算转速,结果电机转得忽快忽慢,查了半天才发现是除法截断导致的误差累积。
那如果我想保留小数呢?很简单,把其中一个操作数转成浮点数:
float result = (float)a / b; // 结果是 2.5
2. 取模运算符 %
% 用来求余数,比如 7 % 3 结果是 1。这个运算符在嵌入式里用途很广,比如判断奇偶、实现循环缓冲区的索引回绕。
小技巧:判断一个数是不是偶数,用 num % 2 == 0 比用位运算更直观。虽然位运算效率更高,但可读性也很重要。
不过要注意,% 的操作数必须是整数。浮点数不能用取模。另外,如果除数为0,程序直接崩溃——这个在写代码时一定要做防御性检查。
二、赋值运算符:= 和它的兄弟们
赋值运算符 = 是C语言里最常用的运算符,没有之一。但很多人容易把它和数学里的等号搞混。
在C语言里,= 是一个操作,它把右边的值赋给左边的变量。比如:
int x = 10; // 把10赋给x
x = x + 5; // 先计算x+5,再把结果赋给x
第二行代码,在数学里是矛盾的,但在C语言里完全合法。它表达的是:取出x当前的值,加上5,再存回x。
复合赋值运算符
C语言提供了一组复合赋值运算符,比如 +=、-=、*=、/=、%= 等。它们的作用是简化代码:
int count = 0;
count += 5; // 等价于 count = count + 5;
count *= 2; // 等价于 count = count * 2;
个人习惯:我在项目里几乎只用复合赋值。原因有两个:一是代码更简洁,二是编译器对复合赋值往往能生成更高效的机器码。比如 count += 1 在某些架构上可能直接对应一条增量指令,而 count = count + 1 需要先读再写。
这里有个表格,列出了常用的复合赋值运算符:
| 运算符 | 示例 | 等价于 |
|---|---|---|
| += | a += b | a = a + b |
| -= | a -= b | a = a - b |
| *= | a *= b | a = a * b |
| /= | a /= b | a = a / b |
| %= | a %= b | a = a % b |
三、自增自减运算符:++ 和 --
这两个运算符是C语言的特色之一。它们让代码更紧凑,但也容易让人困惑。
前置和后置的区别
先看代码:
int i = 5;
int a = ++i; // a = 6, i = 6
int b = i++; // b = 6, i = 7
区别就一句话:前置先加再用,后置先用再加。
++i:先把i加1,然后返回i的新值i++:先返回i的旧值,然后把i加1
我曾经踩过的坑:在一个通信协议解析的代码里,我写了类似 buffer[i++] = data; 这样的语句。本来想先赋值再让i自增,结果因为运算符优先级的问题,实际执行顺序和预期不一样。后来我养成了一个习惯:不要在复杂的表达式里混用自增自减,宁可多写一行代码。
什么时候用前置,什么时候用后置?
如果你只是想让变量自增1,不关心返回值,那两者效果一样。但在嵌入式开发中,我建议优先用前置 ++i。为什么?因为后置需要保存旧值,会多一次拷贝操作。虽然现代编译器会优化,但在某些资源受限的MCU上,前置确实更高效。
一个实用的建议:在for循环里,用 for(i = 0; i < n; ++i) 而不是 i++。虽然差别微乎其微,但好的编程习惯就是这样一点一滴积累起来的。
四、运算符优先级:一个容易翻车的地方
最后聊一个很实际的问题:运算符优先级。我见过太多bug是因为优先级搞错了。
比如:
int x = 5;
int y = x++ * 2 + 3;
这个结果是多少?很多人会算错。实际上,后缀自增的优先级高于乘法和加法,所以先取x的值5,然后x自增为6,再计算5 * 2 + 3 = 13。最终y等于13,x等于6。
我的建议:别去死记硬背优先级表。遇到不确定的地方,直接加括号。括号不仅让代码意图更清晰,也能避免很多隐蔽的bug。代码是写给人看的,不是写给编译器看的。
好了,今天的内容就到这里。算术运算符、赋值运算符、自增自减运算符,这三类运算符虽然基础,但用好了能让代码既高效又优雅。下一节我们会继续聊关系运算符和逻辑运算符,到时候再给大家分享一些实战中的小技巧。
公众号:蓝海资料掘金营,微信deep3321