C具有大量的运算符。表B.1按优先级从高到低的顺序列出了C运算符并指出了它们的结合性。除非特别指明,所有的运算符都是二元的(需要两个操作数)。注意有些二元运算符和一元运算符共享相同的符号但是具有不同的优先级,例如1(乘法)和*(间接)。表之后是每个运算符的总结。
表B.2 C运算符
| 运算符(优先级从高到低) | 结合性 |
|---|---|
| ++(后缀)--(后缀)()(调用函数)[]{}(组合文字).→ | 从左到右 |
| ++(前缀)--(前缀)- + ~ ! sizeof *(取值)&(地址)(type)(都是一元运算符) | 从右到左 |
| (type name) | 从左到右 |
| */% | 从左到右 |
| + -(二者都是二元运算符) | 从左到右 |
| << >> | 从左到右 |
| < ><=>= | 从左到右 |
| == != | 从左到右 |
| & | 从左到右 |
| ^ | 从左到右 |
| | | 从左到右 |
| && | 从左到右 |
| || | 从左到右 |
| ?:(条件表达式) | 从右到左 |
| =*=/= %=+= - =<<=>> = &=丨= ^ = | 从右到左 |
| ,(逗号运算符) | 从左到右 |
B.2.1 算术运算符
| +把右边的值加到左边的值上 |
|---|
| +作为一元运算符时,产生一个大小和符号都同右边值相同的值 |
| -从左边的值中减去右边的值 |
| -作为一元运算符时,改变它右边值的符号 |
| *把左边的值乘以右边的值 |
| /把左边的值除以右边的值;如果两个操作数都是整数,结果要进行截尾 |
| % 得出左边的值除以右边的值时的余数(只对整数) |
| ++ 把右边的变量加1(前缀模式)或把左边的变量加1(后缀模式) |
| --与++类似,不同的是减1 |
B.2.2 关系运算符
每个运算符都把左边的值与右边的值进行比较。
| < | 小于 |
|---|---|
| < = | 小于或等于 |
| == | 等于 |
| > = | 大于或等于 |
| > | 大于 |
| != | 不等于 |
关系表达式
简单的关系表达式由关系运算符与它两侧的操作数组成。如果关系为真,关系表达式值就为1;如果关系为假,关系表达式值就为0。
| 5>2为真,它的值为1 |
|---|
| (2+a) ==a为假,它的值为0 |
B.2.3 赋值运算符
C有一个基本的赋值运算符和几个组合赋值运算符。=运算符是最基本的赋值运算符。
| =把它右边的值赋给它左边的左值(lvalue) |
下列每个赋值运算符都使用指定的运算符,用右边的值来更新左边的左值。我们使用R-H来表示右边, L-H来表示左边。
| + = 把左边的变量加上右边的数,结果放在左边的变量中 |
| - = 从左边的变量中减去右边的数,结果放在左边的变量中 |
| * = 把左边的变量乘以右边的数,结果放在左边的变量中 |
| / = 把左边的变量除以右边的数,结果放在左边的变量中 |
| % = 得到左边的变量除以右边的数时的余数,结果放在左边的变量中 |
| & = 把L-H&R-H的值赋给左边的数,结果放在左边的变量中 |
| | = 把L-HIR-H的值赋给左边的数,结果放在左边的变量中 |
| ^ = 把L-HAR-H的值赋给左边的数,结果放在左边的变量中 |
| >> = 把L-H>>R-H的值赋给左边的数,结果放在左边的变量中 |
| << = 把L-H<<R-H的值赋给左边的数,结果放在左边的变量中 |
例子
| rabbits*=1.6;与rabbits=rabbits*1.6;是相同的 |
|---|
B.2.4 逻辑运算符
逻辑运算符通常使用关系表达式作为操作数。!运算符有一个操作数,其他运算符有两个操作数:一个在左边,另一个在右边。
| && | 与 |
| || | 或 |
| ! | 非 |
逻辑表达式
| 当且仅当两个表达式都为真时,expression1&&expression2的值才为真 |
| 两个表达式至少有一个为真时,expression1||expression2的值就为真 |
| 如果expression的值为假,!expression的值就为真,反之亦然 |
逻辑表达式的计算顺序
逻辑表达式是按从左到右的顺序计算的。一发现可以使整个表达式为假的条件就停止计算。
例子
| 6>2&&3= =3为真 |
| !(6>2&&3= =3)为假 |
| x!=0&&20/x<5只有在x非0时才计算第二个表达式 |
B.2.5 条件运算符
?:具有三个操作数,每个操作数都是一个表达式。它们这样进行排列:expression1? expression2:expression3。如果expression1为真,则整个表达式的值等于expression2的值;否则等于expression3的值。
例子
| (5>3) ?1 :2的值为1 |
| (3>5) ?1 :2的值为2 |
| (a>b) ?a :b的值为a和b中较大的数 |
B.2.6 与指针有关的运算符
| &是地址运算符。当后跟一个变量名时,&得到该变量的地址 |
| *是间接或取值运算符。当后跟一个指针时,*得到存储在指针指向地址中的值 |
例子
&nurse是变量nurse的地址。

其效果是把val赋值为22。
B.2.7 符号运算符
| -是负号,它把操作数的符号变反 |
| +是正号,它不改变操作数的符号 |
B.2.8 结构和联合运算符
结构和联合使用一些运算符来识别单个成员。成员运算符与结构或联合一起使用,间接成员运算符与指向结构或联合的指针一起使用。
成员运算符
“.”与结构或联合名一起使用可以表示该结构或联合的一个成员。如果name是一个结构的名称,member是结构模板中说明的一个成员,那么name.member就表示该结构中的这个成员。name.member的类型是为member指定的类型。在联合中也可以用相同的方式使用成员运算符。
例子

这个语句把一个值赋给结构item的成员code。
间接成员运算符(或结构指针运算符)
“→”与指向一个结构或联合的指针一起使用来表示该结构或联合的一个成员。假定ptrstr是指向一个结构的指针,member是结构模板中说明的一个成员,那么ptrstr→member就表示它所指向结构的成员。在联合中也可以用相同的方式来使用间接成员运算符。
例子

这段程序把一个值赋给item的成员code。以下三个表达式是等效的:

B.2.9 位运算符
除了~之外,以下的所有运算符都是二元运算符。
| ~是一元运算符,它把操作数的每一位都进行反转来得到一个值 |
| &是位与运算符,只有当两个操作数中对应的位都为1时,它产生的值中该位才为1 |
| |是位或运算符,只要两个操作数中对应的位有一位为1,它产生的值中该位就为1 |
| ^是异或运算符,只有两个操作数中对应的位中只有一位为1(不能全为1)时,它产生的值中该位才为1 |
| >>是左移运算符,它的值是把左边操作数中的位向左移动得到的,移动的位数由右边的操作数给出,空出的位用0来填充 |
| <<是右移运算符,它的值是把左边操作数中的位向右移动得到的,移动的位数由右边的操作数给出。对无符号整数来说,空出的位用0来填充;有符号整数的行为依赖于具体的实现 |
例子
假定您写了以下代码:

那么x&y的值为2,因为在x和y中只在第1位两者均为“1”。而y<<x的值为12,因为在y的位组合中,3向左移了两位得到12。
B.2.10 混合运算符
sizeof以char的大小为单位给出它右边操作数的大小。典型地,char的大小为1个字节。操作数可以是圆括号中的类型说明符,例如sizeof(float);也可以是特定的变量、数组名等,例如sizeof foo。sizeof表达式的类型是size_t。
(type)是指派运算符,它把后面的值转换成在圆括号中的关键字指定的类型。例如,(float) 9把整数 9转换为浮点数9.0。
“,”是逗号运算符,它把两个表达式连接到一个表达式中,并保证最左边的表达式最先被计算。整个表达式的值是左边表达式的值。这个运算符通常用来在for循环的控制表达式中包含更多的信息。
例子


