C运算符

使用运算符,对操作数进行运算。运算符和操作数组成了表达式。

操作数可以是常量、字面量、变量、表达式(一个表达式又可以是另一个运算符的操作符)。

有n个操作数的运算符是n元运算符。

一元运算符可以在操作数前面或后面,分别为前置一元运算符、后置一元操作符。

算数运算

C语言支持整数和浮点数的算数运算。

运算符 说明
+a 计算a本身
-a 计算a的相反数
a+b 计算a与b的和
a-b 计算a与b的差
a*b 计算a与b的积
a/b 计算a除以b的商
a%b 计算a除以b余数

关系运算符

关系运算符用来判断整数、浮点数之间的大小、相等关系。

运算符 说明
a<b a是否小于b
a<=b a是否小于或等于b
a>b a是否大于b
a>=b a是否大于或等于b
a==b a是否等于b
a!=b a是否不等于b

逻辑运算符

逻辑运算符用来进行逻辑运算。

运算符 说明
a&&b 与。如果a和b同时为非0,结果为1,否则为0。
a||b 或。如果a和b有一个为非0,结果为1;否则为0。
!a 非。a如果为非0,结果为0;a如果为0,结果为1。

位运算符

位运算符用于对整数的每一位进行运算。

运算符 说明
a&b 位与。对a和b的每一位进行与运算。如果位都为1,返回1;否则为0。
a|b 位或。对a和b的每一位进行或计算。如果有一位为1,返回1;否则为0。
a^b 位亦或。对a和b的每一位进行亦或计算。如果位不相等,返回1;否则为0。
~a 位非。对a的每一位进行非计算。如果位为1,返回0;否则为1。

位移运算符

位运算符用于对整数的每一位进行移动。

运算符 说明
a<<n 左位移运算符。将a的每一位向左移动n位。
a>>n 右位移运算符。将a的每一位向右移动n位。

自增自减运算符

运算符 说明
a++ 后置自增。返回a自身,然后a自身加1。
++a 前置自增。返回a自身加1,然后返回a。
a-- 后置自减。返回a自身,然后a自身减1。
--a 前置自减。返回a自身减1,然后返回a。

赋值运算符

赋值运算符将右边的值赋给左边,左边必须是可变的。

运算符 说明
a=b 赋值。将b的值赋值给a,返回a。

复合赋值运算符

复合赋值运算符可以在变量自身进行运算后赋值。 算数运算符、位移运算符和位运算符支持符合赋值运算。

运算符 说明
a+=b 将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 将a&b的值赋值给a。
a<<=n a<<n的值赋值给a。
a>>=n a>>n的值赋值给a。
a^=b 将a^b的值赋值给a。
a|=b a|b的值赋值给a。
a&=b 将a&b的值赋值给a。
a^=b 将a^b的值赋值给a。

条件运算符

条件运算符可以进行判断。

运算符 说明
a?b:c 如果a为非0,结果为b;否则为c。

其他

运算符 说明
sizeof(a) 计算字节。计算变量或类型a所占字节。
a.b 取成员。取一个结构体或共用体a的成员b。
a->b 取成员。取一个结构体或共用体指针a的成员b。
&a 取地址。取变量a的地址,类型是类型a的指针。
f(a,b,c) 函数调用。 调用函数f。
a[n] 取数组元素。获取数组a的第n+1个元素的值。
(type)a 强制类型转换。将变量a强制转换为type类型。
*p 取值。取指针p指向值。
a,b,c 逗号运算符。从左到右依次计算a,b,c,返回最右边的值。

运算符优先级和结合性

优先级决定有多个运算符的表达式的计算顺序。比如乘法优先于加法。

可以通过圆括号()包围表达式更改优先级。

结合性决定运算符的计算方向,是从左向右还是从右向左。只有一元前缀、条件和赋值运算符是从右到左。

运算符优先级表

名称 运算符 结合性
一元后缀 f(),a[], a->b, a.b ,a++ ,a-- 从左到右
一元前缀 +, -, !, ~, ++a,--a, (type)a,*a, &a, sizeof 从右到左
乘除 *, / ,% 从左到右
加减 +, - 从左到右
移位 <<, >> 从左到右
关系 <, <=, >, >= 从左到右
相等 ==, != 从左到右
位与 & 从左到右
位异或 ^ 从左到右
位或 | 从左到右
逻辑与 && 从左到右
逻辑或 || 从左到右
条件 ?: 从右到左
赋值 =, +=, -=, *=, /=, %=,>>=, <<= ,&=, ^=,|= 从右到左
逗号 , 从左到右

不追求记清每个优先级,建议多使用括号更清晰的显示优先级。

未定义行为

C语言虽然规定了运算符和结合性,但某些表达式的结果是不确定的,是未定义行为。

副作用和序列点

影响变量的值,即是副作用,运算符中,自增自减和赋值运算符是有副作用的。

序列点是表达式中的点。序列点前面的表达式必须求值完毕,并且副作用也已经生效。

逗号,、逻辑与&&、逻辑或||、条件运算符?:中的?是序列点。

存在未定义行为的代码

int i = 100;
int j = (i++) + (i++) + (i++);
printf("%d\n",j);

以上代码的结果是不确定的。3个i++的自增时机没有规定。

确保自增自减等有副作用的运算符在一个表达式中不操作同一个变量多次。