操作符
算术操作符
+
-
*
/
%
%为取模操作符,它接受两个整型操作数,把左操作数除以右操作数,返回的值是余数。
移位操作符
移位操作只是简单地把一个值的位向左或向右移动。
左操作数的值将移动由右操作数指定的位数。
<<
在左移操作符中,值最左边的几位被丢弃,右边多出来的几个空位则由0补齐。
>>
在右移操作符中,从左边移入新位时,可以选择两种方案。
- 逻辑移位
- 左边移入的位用0填充。
- 算术移位
- 左边移入的位由原先该值的符号位决定,从而保证原数的正负形式不变。
- 符号位为1则移入的位均为1。
- 符号位为0则移入的位均为0。
#include <stdio.h>
int count_one_bits(unsigned value) /*返回参数值中值为1的个数*/
{
int ones;
for (ones = 0; value != 0; value = value >> 1) {
if (value % 2 != 0) /*最低位值为1*/
ones = ones + 1;
else /*最低位值不为1*/
continue;
}
return ones;
}
int main() {
int value = 10;
printf("%d" , count_one_bits(value));
}
位操作符
赋值
赋值操作符
赋值操作符用一个等号表示。
赋值操作符把右操作数的值存储于左操作数指定的位置。
x = y + 3;
同时,由于赋值是一个表达式,凡表达式皆有一个值。
所以,赋值表达式的值就是左操作数的新值,它可以作为其他赋值操作符的右操作数。
a = x;
赋值操作符的结合性(求值顺序)是从右到左的。
a = x = y + 3;
等价于
a = (x = (y + 3) );
复合赋值符
a += expression;
等价于
a = a + expression;
唯一的区别在于:
复合赋值操作符的左操作数只求值一次。
单目操作符
单目操作符,也就是只接受一个操作数的操作符。
!
!操作符对它的操作数执行逻辑反操作:
- 如果操作数为真,其结果为假。
- 如果操作数为假,其结果为真。
~
~操作符对整型类型的操作数进行求补操作:
- 操作数中所有原先为1的位变为0。
- 操作数中所有原先为0的位变为1。
++
前缀形式
操作数的值被增加,表达式的值就是操作数增加后的值。
后缀形式
操作数的值被增加,表达式的值是操作数增加前的值。
–
前缀形式
操作数的值被减少,表达式的值就是操作数减少后的值。
后缀形式
操作数的值被减少,表达式的值是操作数减少前的值。
+
+操作符产生操作数。
-
-操作符产生操作数的负值。
&
&操作符产生操作数的地址。
*
间接访问操作符*与指针一起使用,用于访问指针所指向的值。
sizeof
sizeof操作符判断操作数的类型长度,以字节为单位表示。
(类型)
(类型)操作符被称为强制类型转换,它用于显示地把表达式的值转换为另外的类型。
关系操作符
这些操作符产生的结果都是一个整型值,而不是布尔值。
- 如果两端的操作数符合操作符指定的关系,表达式的结果为1。
- 如果不复符合,表达式的结果是0。
>
>=
<
<=
!=
==
逻辑操作符
&&
expression1 && expression2
- 如果expression1和expression2的值都是真的,那么整个表达式的值也是真的。
- 如果两个表达式中的任何一个表达式的值为假,那么整个表达式的值变为假。
短路求值
&&操作符的左操作数总是首先进行求值,如果它的值为真,然后就紧接着对右操作数进行求值。如果左操作数的值为假,那么右操作数便不再进行求值,因为整个表达式的值肯定是假的。右操作数的值已经无关紧要了。
||
expression1 || expression2
- 如果expression1和expression2的值都是假的,那么整个表达式的值也是假的。
- 如果两个表达式中的任何一个表达式的值为真,那么整个表达式的值变为真。
短路求值
||操作符首先对左操作数求值。如果它的值是真,右操作数便不再求值,因为整个表达式的值已经确定。
条件操作符
expression1 ? ecpression2 : expression3
首先计算expression1,如果它的值为真,那么整个表达式的值就是expression2的值,expression3不会进行求值。
但是,如果expression1的值为假,那么整个表达式的值就是expression3的值,expression2不会进行求值。
逗号操作符
expression1, expression2, expression3, expression4,..., expressionN
逗号表达式用于将两个或多个表达式分隔开来。
这些表达式自左向右逐个进行求值,整个逗号表达式的值就是最后的那个表达式的值。
布尔值
C并不具备显示的布尔类型,所以使用整数来代替。
规则是:
0是假,任何非0值都是真。
表达式求值
类型转换
隐式类型转换
C的整型算术运算总是至少以默认整型类型的精度来进行的。
为了获得这个精度,表达式中的字符型和短整型操作数在使用之前被转换为普通整型。这种转换称为整型提升。
算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作无法进行。
下面的层次体系称为寻常算术转换:
- long double
- double
- float
- unsigned long int
- long int
- unsigned int
- int
如果某个操作数的类型在上面这个列表中排名较低,那么它首先将转换为另外一个操作数的类型,然后执行操作。
操作符属性
- 优先级
- 结合性
- 是否控制执行顺序
两个相邻的操作符哪个先执行取决于它们的优先级,如果两个的优先级相同,那么它们的执行顺序由它们的结合性决定。
结合性就是一串操作符是从左向右依次执行还是从右向左逐个执行。
最后,%%、||、?:、,这四个操作符可以对整个表达式的求值顺序施加控制,它们或者保证某个子表达式能够在另一个子表达式的所有求值过程完成之前进行求值,或者可能使某个表达式被完全跳过不再求值。