目录
一、操作符分类
操作符可以分为:算术操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号表达式、下标引用函数调用和结构成员操作符等
二、算术操作符
1.算数操作符主要包括:
+(加) -(减) *(乘) /(除) %(取模,取余数)
2.注意事项
(1)除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
(2)对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法,例如4/1.0或4.0/1都执行浮点数除法。
(3)% 操作符的两个操作数必须为整数。返回的是整除之后的余数。
(4)负数的取模计算方式与编译器有关,例如-7%3可以等于-1也可以等于-2
三、移位操作符
1.原码、反码与补码
首先,正数的原反补码完全相同,负数的原反补码遵循以下规则:
原码:数据的二进制代码,代表了变量的值属性
反码:除符号位全部按位取反
补码:反码加一,在只要在内存中存储和程序使用数据时都改变补码
2.左移操作符:
(1)移位规则:左边抛弃、右边补0
3.右移操作符:>>
(1)移位规则:包括算术右移和逻辑右移两种方式,两种方式的选取取决于编译器
(2)算术右移:右边抛弃,左边补齐符号位
(3)逻辑右移:右边抛弃,左边直接补零
注意:移位操作符的操作数只能是非负整数。
四、位操作符
1.位操作符主要包括:
& (按位与)| (按位或)^ (按位异或)
2.规则
(1)& 按位与规则:二进制补码对应位均为1时,新产生的二进制代码为1否则为0
(2)| 按位或的规则:二进制补码对应位有一个为1时,新产生的二进制代码为1否则为0
(3)^ 按位异或的规则:二进制补码对应位不相同时时,新产生的二进制代码为1否则为0
(4)对于两个变量a和b,存在a^0=a,a^a=0,。
(5)多个^的表达式计算值与计算顺序无关而且也满足交换律,比如:a^b^b=a^(b^b)=a^0=a
3.面试题
不能创建临时变量(第三个变量),实现两个数字的交换。
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
printf("交换前:a=%d,b=%d", a, b);
a = a ^ b;
b = a ^ b;//此时的a相当于原来的a^b
a = a ^ b;//此时的b=a,a依旧相当于原来的a^b
printf("交换后:a=%d,b=%d", a, b);
return 0;
}
五、逻辑操作符
&&(逻辑与) ||(逻辑或)
逻辑与是在前后表达式均为真时整个表达式为真,逻辑或是在前后表达式有一个为真时整个表达式为真
区分逻辑与和按位与:1&2----->0 、1&&2---->1
区分逻辑或和按位或:1|2----->3 、1||2---->1
C语言中0为假,非零为真。
六、单目操作符及其他操作符
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符,用于指针)
(类型) 强制类型转换
还有其他操作符,可以看看我之前的博客(偷懒):拒绝从入门到入土:初识C语言_聪明的骑士的博客-CSDN博客https://blog.csdn.net/qq_65285898/article/details/124021746?spm=1001.2014.3001.5502
六、表达式求值
1.整型提升与数据截断
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
比如说两个字符型变量相加就需要把这两个变量转化为int类型(整型提升),然后再进行相加,最后再将结果转化为字符类型(截断)。
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0
2.算数转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
比如:一个int类型的变量与一个double类型的变量相加,结果为double类型。也就是说,不同类型的数据运算,在其计算时变量的大小至少为一个整形大小,结果默认为精度较高的数据类型。
3.操作符的属性
(1)复杂表达式的求值有三个影响的因素。
- 操作符的优先级:规定了相邻操作符的执行顺序
- 例如:a+b*c中由于*的优先级高于+,所以先执行*后执行+
- 操作符的结合性:相邻的两个运算符的具有同等优先级时,决定表达式的结合方向,有些需要让表达式从左向右计算(L-R),有些需要从右向左计算(R-L),还有些并不适用(N/A)
- 例如:a=b=c中由于前后操作符相同,也就是说优先级相同,而=的结合性为R-L,也就是操作符从右到左执行,相当于a=(b=c)把c赋值给b,然后a=b把b赋值给a,这就是操作符的结合性。
- 是否控制求值顺序:最具代表性的是逻辑操作符。
- 例如对于exp1 && exp2的条件,exp1为假时exp2是不会计算的,同样对于exp1 || exp2的条件,exp1为真时exp2也是不会计算的。
(2)附表:
(3)由于操作符的优先级适用于相邻操作符,所以复杂表达式的值在不同的编译器下是不同的。
比如:
#include<stdio.h>
int main()
{
int i = 10;
i = i-- - --i * ( i = -3 ) * i++ + ++i;
printf("i = %d\n", i);
return 0;
}
在不同环境下i = i-- - --i * ( i = -3 ) * i++ + ++i的计算结果:
Tandy 6000 Xenix 3.2 | -128 |
Think C 5.02(Macintosh) | -95 |
IBM PowerPC AIX 3.2.5 | -86 |
Sun Sparc cc(K&C编译器) | -85 |
gcc,HP_UX 9.0,Power C 2.0.0 | -63 |
所以,在我们写代码的时候注意避免过于复杂的表达式。