一. 操作符
1. 算术操作符
+ - * / %
除了%之外其余的几个操作符既可以用于计算整型也可以用于计算浮点型数据,%只能计算整型数据,得到的结果是余数
2. 移位操作符
<< 左移位操作符 >> 右移位操作符
<<左移时,值最左边的几位被丢弃,右边多出来的几个空位由0补齐。
>>右移时,从左边移入新位有两种方式。一种方案是逻辑移位,左边移入的数由0填齐;另一种是算术移位,左边移入的数由原先该值得符号位决定,符号位为1则移入的为均为1,符号位为0则移入的位为0。
警告:
标准说明无符号执行的所有的移位操作都是逻辑移位,但是对于有符号值,移位操作取决于自己的编译器。一个程序如果使用有符号是数的右移操作,那么它是不可移植的。
如果出现下面的移位操作:a<<-5
标准说明这类移位是未定义的,所以它由编译器来决定,这种结果是不可预测的,使用这样的程序也是不可移植的,我们应该避免这类的移位操作。
3. 位操作符
& | ^
&与操作符:当两个位进行与操作时,如果两个位都是1,结果为1,否则为0;
|或操作符:两个位中有至少有一个位为1,结果为1,否则为0;
^异或操作符:两个位不同时结果为1,如果两个位相同,结果为0.
上面的三个操作符要求两个数位整型。
下面介绍几种位的操纵:
(1) 将某一位置为1
value = value | (1<<number)
(2) 将某一位置为0
value = value &~ (1<<number) ~是取反的意思
(3) 对某一位进行为1测试
value = value &(1<<number)
如果该位已经是1,则表达式的结果为非0值
4. 赋值
=
赋值操作符的结合性是从右到左,所以下面的这个语句a = x = y + 3;他的意思和下面的语句是等价的a = (x = y + 3);
复合赋值符
+= -= *= /= %=
<<= >>= &= ^= |=
5. 单目操作符
! ++ - & sizeof
~ -- + * (类型)
!操作符,对它的操作数进行逻辑反操作,如果操作数为真,其结果为假,如果操作数为假,其结果为真。这个操作数的结果只有两个值,0或1。
~操作符,对整类型的操作数进行求补操作,操作数中原先所有为1的位置为0,为0的位置为1。
-产生的操作值为负值
&操作数产生它的操作数的地址
*操作符是间接访问操作符,它与指针一起使用,用于访问指针所指向的值。sizeof操作符判断它的操作数的类型长度,以字节为单位表示。
(类型)操作符是强制类型转换,它用于显式的将表达式的值转换为另外的类型。
++和—操作符,注意前置和后置就好,前置是先计算后使用,后置是先使用后计算
6. 关系操作符
> >= < <= != ==
需要注意的是,这些操作符产生的结果不是布尔值,而是整型值,如果对返回1,如果不对返回的是0。这里我们在使用==操作符的时候,应该特别注意的是不要把==写成了=。
7. 逻辑操作符
&& ||
&& 逻辑与 expressionl1 && expression2 两真才真,一假就假
一个有趣的点就是,&&的优先级比<,>等的优先级低,所以如果是下面的表达式, a>5 && a<10,则实际的求值顺序是下面这个样子的:(a>5)&& (a<10),但是有一点需要引起大家的注意,就是如果a>5这个表达式的结果为假,那么后面的a<10根本不进行判断,并且整个表达式的结果为假。
|| 逻辑或 expressionl1 || expression2 一真就真,两假才假
逻辑或操作符也有一个有趣的特点就是,如果第一个表达式的结果是真,那么第二个表达式也不进行求解,并且整个表达式的结果为真。
上面的这两种行为被称为“短路求值”
8. 条件操作符
expressionl1 ? expression2 : expression3 操作的过程是,首先判断expressionl1的值是不是真,如果为真则执行expression2,如果为假则执行expression3
9. 逗号操作符
expressionl1 , expression2 , …… , expression 操作的过程是从左到右依次对各个表达式进行求值,整个表达式的值就是最后一个表达式的值。
10. 下标引用、函数调用和结构成员
下标引用主要出现在数组中arry[下标] 和 *( arry + (下标) )
函数调用操作符 就是在一个函数中调用另一个函数
结构成员 是在结构体中使用 . 和 –> 用于访问结构体的一个成员,我们需要注意一点是,当我们访问结构体的一个成员的时候,我们已经知道这个结构体了,我们可以使用例如s.a,但是如果我们此时拥有的是指向该结构体的一个指针而不是这个结构体,那么我们应该使用的是 -> 。
二. 布尔值
C语言不具备显示的布尔值,但是可以用整数来代替,其规则是0是假,非0为真
三. 左值和右值
左值是放在赋值符左边的东西,右值就是放在赋值符号的右边的东西。
简单的理解一下就是左值就是这个变量本身,右值则是变量的内容,以后还会详细介绍关于左值和右值的理解
四. 表达式求值
1. 隐式类型转换
C语言一般为了获得一个精度,表达式中的字符型和短整型首先被转换成普通的整型,然后再进行计算,这种方式被称为整型提升。如下面的求值例子:
char a,b,c;
a = b + c;
b和c的值被提升为普通整型,然后进行加法运算,加法运算的结果将被截短,然后再存储在a中。
2. 算术转换
如果某个操作符的各个操作数的类型不一样,那么除非其中一个转换成另一个,否则无法计算,下面的层次被称为寻常算术转换。
long double
double
float
usinged long int
long int
usinged int
int
如果某个操作数的类型在上面的列表排名较低,那么它首先将转换成比它排名高的,然后再进行计算。
3. 操作符的属性
复杂表达式的求值顺序是由3个因素决定的:操作符的优先级、操作符的结核性和操作符是否控制执行的顺序。
下表显示了各个操作符的优先级
4. 优先级和求值的顺序
两个相邻的操作符的执行顺序由它们的优先级决定,如果它们的优先级相同,它们的执行顺序由它们的结合性决定。除此之外,编译器可以自由的决定使用任何顺序对表达式进行求值,只要它不违背逗号、&&、||、和?:操作符所施加的操作。
看下面的语句:
a * b + c * d + e * f
这里并没有任何规则要求所有的乘法首先进行,也没有规定这几个乘法之间谁先执行。优先级在这里没有作用,优先级只对相邻的操作符的执行顺序起作用。
下面的这条语句是危险的:c + --c,因为在不同的编译器下面结果是不一样的,感兴趣的同学可以上网搜索或者自己测试分析一下。