C语言 操作符
初学C语言者 人气:0前言
操作符主要内容包括:各种操作符的介绍,用表达式求值。
1、操作符的分类
- 算术操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用、函数调用和结构成员
2、算术操作符
+ - * / % (加法 减法 乘法 取余 取模)
int main() { int a = 9 / 2;//4 float b = 9 / 2; int c = 9.0 / 2; float d = 9.0 / 2;//4.5 float e = (float)9.0 / 2; printf("%d\n", a); printf("%f\n", b); printf("%d\n", c); printf("%f\n", d); printf("%f\n", e); return 0; }
运行结果见下图:
通过例子可发现,变量的类型使用错误的话,结果也是错误的
- 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数
- 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法
- % 操作符的两个操作数必须为整数。返回的是整除之后的余数
3、移位操作符
移位操作符的操作数只能是整数
<< 左移操作符
>> 右移操作符
3.1 左移操作符
- 移位规则:左边抛弃、右边补0
- 整数是 int 型,占4个字节,有32位表示。其中最高位表示符号,0为正,1为负
- 整数在内存中存储的是补码的二进制,正数的原码、反码、补码是相同的
- 操作符对整数操作的流程:
(1)先将整数的原码转换成反码
(2)反码 +1转换成补码
(3)最后对整数的补码进行操作
(4)操作结束后,将操作后的补码 -1 转换成反码
(5)将反码转换成最终的原码
- 函数printf打印的是整数的原码
3.1.1 正数左移1位
代码如下(示例):
int main() { int a = 5; int b = a << 1;//操作的补码二进制位,a本身结果不变 printf("%d\n", a);//打印5 printf("%d\n", b);// -10 return 0; }
结果运行见下图,与分析的结果一致,左移1位的效果相当于乘以2,左移在51单片机、STM32中,操作寄存器会经常用到。
3.1.2 负数左移1位
int main() { int a = -5; int b = a << 1;//<< >> 操作的二进制位 printf("%d\n", a);//打印-5 printf("%d\n", b);// -10 return 0; }
运行结果见下图,和分析的结果一致
3.2 右移操作符
右移移位规则运算分两种:
- 逻辑移位:左边用0填充,右边丢弃
- 算术移位:左边用原该值的符号位填充,右边丢弃
3.2.1 正数右移1位
int main() { int a = 5; int b = a >> 1;//右移不一定是除2 printf("%d\n", a);//打印-5 printf("%d\n", b);// -3 return 0; }
下面分析右移的过程:正数的原码、反码、补码一样
00000000 00000000 00000000 00000101 //5的二进制补码
//算术右移:左边用原该值的符号位1填充,右边丢弃1
00000000 00000000 00000000 00000010 //右移后的补码
//右移后的补码就是右移后的原码 2
结果见下图:
3.2.2 负数右移1位
int main() { int a = -5; int b = a >> 1;//右移不一定是除2 printf("%d\n", a);//打印-5 printf("%d\n", b);// -3 return 0; }
下面分析右移的过程:
10000000 00000000 00000000 00000101 //-5的二进制原码
11111111 11111111 11111111 11111010 //反码
11111111 11111111 11111111 11111011 //补码:反码+1
//算术右移:左边用原该值的符号位1填充,右边丢弃1
11111111 11111111 11111111 11111101 //右移后的补码
11111111 11111111 11111111 11111100 //反码:补码-1
10000000 00000000 00000000 00000011 //原码 -3
结果见下图:
3.3 移位操作符说明
注意事项:
- 右移操作符采用逻辑移位还是算术移位,取决于电脑编译器,我的是算术移位,所以举例以算术移位分析的,逻辑移位分析流程一样
- 对于移位运算符,不要移动负数位,这个是标准未定义的,例如:
int num = 10; num>>-1;//10右移-1位,这是错误的表达
4、位操作符
位操作符有:
& //按位与 相同为1, 相异为0
| //按位或 有1为1, 全0为0
^ //按位异或 相同为0, 相异为1
//注:他们的操作数必须是整数
int main() { int a = 3; int b = -5; int c = a & b; int d = a | b; int e = a ^ b;//异或 //对应的二进制位:相同位0,相异为1 printf("%d\n", c);// 打印3 printf("%d\n", d);// -5 printfan("%d\n", e);// -8 return 0; }
00000000 00000000 00000000 00000011 3的补码
11111111 11111111 11111111 11111011 -5的补码
//按位与: 相同为1, 相异为0
00000000 00000000 00000000 00000011 3的补码,原码表示3
//按位或: 有1为1, 全0为0
11111111 11111111 11111111 11111011 -5的补码,原码表示-5
//按位异或: 相同为0, 相异为1
11111111 11111111 11111111 11111000 补码
11111111 11111111 11111111 11110111 反码
10000000 00000000 00000000 00001000 原码 -8
输出结果见下图,与分析一致:
4.1 练习 1
不能创建临时变量(第三个变量),实现两个数的交换
int main() { int a = 3; int b = 5; printf("a=%d b=%d\n", a, b); //第一种,常用的方法,创建中间变量 int tmp = a; a = b; b = tmp; //第二种,不创建变量 a = a + b; b = a - b; a = a - b; //第三种,不创建变量,很难想到 a = a ^ b; b = a ^ b; a = a ^ b; printf("a=%d b=%d\n", a, b); return 0; }
4.2 练习 2
求一个整数存储在内存中的二进制中1的个数
//举例: 5 &1, 然后右移1位, 再&1
//00000000 00000000 00000000 00000101
//00000000 00000000 00000000 00000001
int main() { int num = 0; scanf("%d", &num); int i = 0; int cnt = 0; //位操作 for ( i = 0; i < 32; i++) {//每次右移一位就 &1 if (1==((num>>i)&1)) { cnt++;//所有位与1,相同为1,相异为0 } } printf("%d", cnt); return 0; }
总结
本文对部分操作符进行了,介绍,也分析了操作符的具体实现过程,这里了解原理即可,具体运算交给计算机执行,没必要每个都自己画图分析,耗时,不细心可能还会出错,32位二进制建议大家划分成4个字节,8位一组,好看一些,这在STM32 单片机对寄存器操作时,经常这样划分,一目了然。
加载全部内容