二元算术运算符包括:+
(加)、-
(减)、*
(乘)、/
(除)、%
(取模)
%
y的结果是x除以y的余数,当x能被y整除时,其值为0。+
和-
具有相同的优先级,它们的优先级比*
、/
和%
的优先级低*
、/
和%
的优先级低于一元运算符+
和-
关系运算符包括:>
、 >=
、 <
、<=
<
lim - 1 等价于 i <
(lim - 1)==
、!=
),因此0 !=
a <=
1 等价于 0 !=
(a <=
1)逻辑运算符包括:&&
(与) 、||
(或) 、!
(非)
&&
或||
连接的表达式按从左到右的顺序进行求值,并且,在知道结果值为真或假后立即停止计算(短路)。&&
优先级高于||
,但是两者都比关系运算符和相等性运算符的优先级低C语言提供了两个用于变量递增与递减的特殊运算符。自增运算符++
使其操作数递增1,自减运算符--
使其操作数递减1。
++
与--
这两个运算符特殊的地方在于:它们既可以用作前缀运算符(++n),也可以用作后缀运算符(n++)。在这两种情况下,其效果都是将变量n的值加1。但是,它们之间有一点不同。表达式++n先将n的值递增1,然后再使用变量n的值;而表达式n++则是先使用n的值,然后再将n的值递增1。C语言提供了6个位操作运算符。这些运算符只能作用于整型操作数,即只能作用于带符号或无符号char、short、int、long类型:
运算符 | 说明 | 运算规则 |
---|---|---|
& | 按位与(AND) | 参与运算的两个二进位都为1,结果位才为1;1&1=1, 1&0=0,0&1=0,0&0=0 |
| | 按位或(OR) | 参与运算的两个二进位只要有一个为1,结果位就为1;1|1=1, 1|0=1, 0|1=1, 0|0=0 |
^ | 按位异或(XOR) | 参与运算的两个二进位不同,结果位为1,相同,结果位为0;1^1=0, 1^0=1, 0^1=1, 0^0=0 |
<< | 左移 | m< |
>> | 右移 | m>>n, 将二进制位右移n位 |
~ | 按位求反(一元运算符) | 0变1,1变0 |
&
经常用于屏蔽某些二进制位(x&1=x; x&0=0,其中x取值0或者1),比如:|
经常用于将某些二进制位置为1(x|
1=1; x&0=x,其中x取值0或者1),比如:|
SET_ON; 该语句将n中对应于SET_ON中为1的那些二进制位置为1。&
、|
与逻辑运算符&&
、||
,比如:#include
main()
{
int x = 5; // 0000 0101
printf("%d\n", x << 2); // 0001 0100 20=x*4
printf("%d\n", x >> 2); // 0000 0001 1=x/4
unsigned int y = 5; // 0000 0101
printf("%d\n", y >> 2); // 0000 0001 1=x/4
signed int z = -5; // 1000 0101原码 --> 1111 1010 反码(原码取反) --> 1111 1011 补码(反码加1)
printf("%d\n", z >> 2); // 1111 1011(-5补码) -->右移2位,左边空位补符号位 1111 1110补码 --> 1111 1101反码 --> 1000 0010原码 -2
return 0;
}
关于负数的二进制可以参考我的另一篇博客:负数的二进制
int a = 64 + 16 + 1;
// 077八进制-->十进制63-->二进制 011 1111 -->取反 0100 0000
// 0101 0001 a
//&0100 0000 ~077
//=0100 0000
a = a & ~077; // 将把a的最后六位设置为0
printf("%d\n", a);
printf("%d\n", ~0); // -1 1000 0001 -> 1111 1111(补)
printf("%d\n", ~0 << 2); // 1111 1111(补) << 2 --> 1111 1100(补) 1111 1011(反) 1000 0100(原) -4
printf("%d\n", ~(~0 << 2)); // 1111 1100 -->取反 0000 0011
printf("%d\n", getbits(13, 2, 2));
// 返回整数x从第p位(从右边数,假定最右边是第0位)开始,往右数n位的值,也即除了这n位,其左边位都置0
unsigned getbits(unsigned int x, int p, int n) {
// 0000 1101 x=13 p=2 n=2
// 0000 0110
//&0000 0011
// 0000 0010 2
return (x >> (p + 1 - n)) & ~(~0 << n);
}
x >> (p + 1 - n) 将要求的n位数移到最右端,其中p+1-n就是要求的n位数的右端的没用的位数;
~0所有位都为1;
~0<
在赋值表达式中,如果表达式左边的变量重复出现在表达式的右边,如:
i = i + 2,
则可以将这种表达式缩写为下列形式:
i += 2,其中的+=属于赋值运算符
大多数二元运算符都有相应的赋值运算符op=,其中op可以是下面这些运算符之一:
+
-
*
/
&
<<
>>
&
^
|
下面这组语句:
if (a > b)
z = a;
else
z = b;
用于求a和b中的最大值,并将结果保存到z中。条件表达式(使用三元运算符" ? : ")提供了另外一种方法编写这段程序及类似的代码段。在表达式
expr1 ? expr2 : expr3
中,首先计算expr1,如果其值不等于0(为真),则计算expr2的值,并以该值作为条件表达式的值,否则计算expr3的值,并以该值作为条件表达式的值。expr2和expr3中只能有一个表达式被计算。因此,以上语句可以改写为:
z = (a>b) ? a : b; /* z = max(a,b) */
下表总结了所有运算符的优先级与结合性,同一行中的各运算符具有相同的优先级,各行间从上往下优先级逐行降低。
运算符 | 结合性 |
---|---|
() [ ] -> . | 从左至右 |
! ~ ++ – + - * (type) sizeof | 从右至左 |
* / % | 从左至右 |
+ - | 从左至右 |
<< >> | 从左至右 |
< <= > >= | 从左至右 |
== != | 从左至右 |
& | 从左至右 |
^ | 从左至右 |
| | 从左至右 |
&& | 从左至右 |
|| | 从左至右 |
? : | 从左至右 |
= += -= *= /= %= &= ^= |= <<= >>= |
从右至左 |
, | 从左至右 |