目录
前言
本次学习内容:原码、反码、补码、操作符、操作符在内存中的存储
1、进制和原码、反码、补码
大家都知道整数在内存中以二进制的形式存储,那你知道具体是怎么存储的吗?其实啊,它是以补码的方式存储的。下面就由我们一起来看看。
首先1个整数占四个字节,每个字节占8个比特位,所以一个整数占32个比特位,举个例子:
整数3,它的二进制(0~1)位是00000000000000000000000000000011,共32个比特位。同时3也可以用八进制(0~7)表示,十六进制(0~15)表示,而2本身是十进制(0~9)表示的。
那么什么是原码、反码、补码,他们之间有什么关系呢?
整数的二进制表示要分正整数和负整数
正整数:原码反码补码一样
负整数:原码:即上面所说的二进制位
反码:保留符号位->最高位,其他位置按位取反
注意:最高位是符号位 0->正数 1->负数
补码:反码+1,内存中,整数在内存中存的是补码
例子:5
原码反码补码都为:
00000000000000000000000000000101
例子:-5(位数没变,间距问题)
原码:10000000000000000000000000000101
反码:11111111111111111111111111111010
补码:11111111111111111111111111111011
2、操作符解析
2.1、算数操作符
+ - * / %
注意:/分整数除法和小数除法,要想实现小数除法,/左右至少有一个浮点数
% 取模操作符的两端必须是整数。
2.2、移位操作符
意义:移位指向左向右移动该整数的补码,不支持小数移位,也不支持移负数位或小数位
如:1.5<<1,另外a<<-1或a<<1.5也是错的
2.2.1、左移操作符(<<)
遵循:左边丢弃,右边补0
例子:
小结论:左移n位,相当于a*2^n
2.2.2、右移操作符(>>)
1、算数右移:右边丢弃,左边补符号位
2、逻辑右移:右边丢弃,左边补0
注意:一般来说,编译器都是用的算数右移。
例子:
7->3
-7->-4
右移的情况和左移差不多
2.3、位操作符
意义:位指的是按二进制位
2.3.1、&--按位与
遵循:有0取0,同1才1
例子:
2.3.2、|--按位或
遵循:有1则1,同0才0
2.3.3、^--按位异或
遵循:相同取0,不同取1
^异或结论:
a=3 b=-5
a^0=a a^a=0 并且^满足交换律
所以a^b^a=b b^a^b=a
例子:
要求:不创建临时变量实现两个数的交换
代码如下
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
//不创建临时变量,实现两个数的交换
//如果可以创建临时变量则和平时的交换一样
int main()
{
int a = 10;
int b = 20;
printf("交换前:%d %d\n", a, b);
法一 要考虑a+b可能溢出的问题
//a = a + b;
//b = a - b;
//a = a - b;
//printf("交换后:%d %d", a, b);
//法二
a = a ^ b;
b = a ^ b; //此时的a=10^20
a = a ^ b;
printf("交换后:%d %d", a, b);
return 0;
}
2.3.4、应用
编写一个代码:求一个整数存储在内存中的二进制1的个数
代码如下:
#include<stdio.h>
int main()
{
int a = 5;
int cnt = 0;
int i = 0;
for(i=0;i<32;i++)
{
if(a & 1)
{
cnt++;
}
a >>= 1;
}
printf("%d\n", cnt);
return 0;
}
2.4、单目操作符
!逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 求长度(单位是字节)(而strlen()是一个求字符串长度的函数)
~ 对一个数的二进制(补码)按位取反
-- 前置、后置
++ 前置、后置
* 间接访问操作符(即解引用操作符,配合指针使用)
(类型) 强制类型转换
2.4.1、应用~、&、|
编写一个代码:将一个数的二进制的某一位值改变
总结:把第i位改为1:a|=1<<i 其中(0<=i<=32)
把第i位改为0:a&=~(1<<i) 其中(0<=i<=32)
代码如下:
#include<stdio.h>
int main()
{
int a = 13;
printf("改变前:%d\n", a);
a |= 1 << 1;
printf("0->1:%d\n", a);
a &= ~(1 << 1);
printf("1->0:%d\n", a);
return 0;
}
演示:
2.5、逻辑操作符
&& --左边为假,右边就不计算了
|| --左边为真,右边就不计算了
2.6、条件操作符
遵循:
a>b?a:b
a>b为真,结果为a(b不计算),否则为b(a不计算)
2.7、逗号表达式
遵循:','前的式子依次计算,结果为最后一个表达式的结果
如:a=1,b=2 c=(a>b,a=b+10,a,b=a+1)--->c=13
2.8、访问结构体操作符
如struct Stu* p=&a ,a是一个结构体
.(点) --结构体+成员名 (*p).
-> --结构体指针+成员名 p ->
2.9、表达式求值
遵循:考虑优先级和结合性,还有一个:隐式类型转换
隐式类型转换:当表达式中的字符或短整型在使用前被转换为整形,这种情况叫整形提升,
2.9.1、整形提升
整形提升:高位补符号位,低位不变
例子:
如char a=1;
变量a的二进制补码中只有8个比特位
:00000001
因a为有符号的char,整形提升时,高位补符号位,结果为
:00000000000000000000000000000001
代码如下(证明整形提升):
//证明整形提升
#include<stdio.h>
int main()
{
char c = 5;
printf("c的大小:%d\n", sizeof(c));
printf("c的大小:%d\n", sizeof(+c));
return 0;
}
演示:
整形提升的意义:
表达式的整形运算要在CPU的相应运算器件内执行,CPU内的整形运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU通用寄存器的长度。
通用CPU是难以直接实现两个8比特字节直接相加运算,所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int 或unsigned int,然后才能送入CPU去执行运算
2.9.2、算术转换
和整形提升相对地,类型大小>=int时,会发生算术转换
总结
以上就是今天要讲的内容,本文介绍了移位操作符,位操作符,按位取反操作符等等及它们的应用,还有整形提升和算数转换等内容