1.操作符
(1)按位取反~
C语言中,0的符号位是0。
例:int a = 0;
~a = -1
按二进制补码取反,符号位也要取反,打印的是原码。
把一个数的二进制位的第n位变成1:a = a | (1<<n-1)
应用场合
把一个数的二进制位的第n位变成0:a=a&(~(1<<n-1))
(2)前置++ -- 后置++ --
自增/自减可以使变量变化,但如果只是变量运算,不赋值给自身,变量的值不变。
例:
a = 1 a-- 则,a = 0
a = 1 a-1 则,a = 1
(3)强制类型转换
例:int a = (int) 3.14;
(4)关系操作符
> >= < <= != ==
(5)逻辑操作符
&& ||
逻辑与 &&,只要左边为假,右边就不执行了。
逻辑或 ||,只要左边为真,右边就不执行了。
短路特性
i=0 a=0 b=2 c=3 d=4
例1:
i=a++ & ++b && d++
a=0
所以,i=0 a=1 b=2 c=3 d=4
例2:
i=a++ || ++b || d++
所以,i=1 b=3 c=3 d=4
(6)条件操作符
exp1?exp2:exp3
(7)逗号表达式
exp1,exp2,exp3,exp4,exp5,exp6...expn
从左到右依次执行,整个表达式的结果是最后一个表达式的值。
while(a,b,c)相当于 do{a,b} while(c)
(8)其它操作符
[]:操作数为一个数组名+一个索引值
():操作数为函数名+实参
.:结构体变量.成员
->:结构体变量的指针->成员
2.表达式求值
(1)概述
win+R,calc 计算器
操作符的优先级和结合性
表达式求值
操作数在求值过程中可能需要转化成其它类型
(2)隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的,为了获得这个精度,表达式中的字符和短整型操作数在使用之前,会被转换成普通整型。(整型提升)
例:
char a = 3;
char b = 127;
char c = a+b;
则c=-126
a=3,000...11(32位),char(8位)截断,00000011
b=127,000...1111111,01111111
char是有符号的
char c = a+b;(整型提升)最高位看作符号位
a=00000011,正数的整型提升补0,000....11(32位)
b=0000...1111111(32位)
a+b=000...10000010(32位)——>截断成char型 10000010 ——> 负数整型提升补1
11111...10000010(补码)——> 11111...10000001(反码)——>10000...01111110(-126)
无符号数整型提升,补0。
整型提升,是为了匹配CPU内整型运算器(ALU)的操作数的字节长度(int),同时也是CPU的通用寄存器长度。
只要参与表达式运算,就会发生整型提升。
例1:
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if(a==0xb6) //0x,十六进制符号
{
printf("a");
}
if(b==0xb600)
{
printf("b");
}
a和b都是整型提升了,所以都不相等。
例2:
%u是无符号十进制整数
char c = 1;
sizeof(c) 1
sizeof(c+1) 4
sizeof(!c) 4
(3)算术转换
某个操作符的各个操作符属于不同类型,则会把它们转换成同一种类型。
寻常算术转换:
long double double float unsigned long int long int unsigned int int
操作符属性:优先级、结合性、是否控制求值顺序
问题表达式:
例1:
a*b+c*d+e*f
无法确定真正的计算顺序,虽然不影响结果,但计算路径不唯一。
例2:
c+ --c //--高于+
无法得知,先获取C,还是先计算--c
例3:
int i = 10;
i=i-- - --i*(i=-3)*i++ + ++i;
不同编译器下有不同的结果
例4:
int fun ()
{
static int count = 1; //延长局部变量的生命周期,之后不用管这条语句
return ++count;
}
int main ()
{
int answer;
answer=fun()-fun()*fun(); //这三个函数的调用顺序无法得知
printf("%d\n",answer);
return 0;
}
例5:
int i = 1;
int a = (++i)+(++i)+(++i);
不清楚那个++i先被计算
表达式最终要有一个唯一确定的计算路径