数据在内存中存储的规则
数据在内存中的存储为二进制
整形在内存中有三种形式,原码、反码、补码
整数由两种形式组成
无符号位的原码反码补码相同
有符号位分为最高位和数值位组成
正数的原反补相同
负数的三种方法各不相同
原码:直接将数值按照正负数翻译出来的二进制得到的就是原码。
反码:将原码的符号位不变,其他的依次按位取反得到反码
补码:反码+1得到的补码
大端字节序和小端字节序概念
小端字节序存储:一个数据的低位字节数据,存放在内存到的低地址处,高位字节的数据,存放在内存中高地址处
大端字节序存储:第一个数据的低位字节数据存放在内存的高地址处,高位字节的数据存放在内存中低地址处
int main()
{
int a=0x11223344;
//11 22 33 44
//这种存储方式是大端字节序
//44 33 22 11
//这种存储方式是小端字节序存储
//一个16进制位可以换四个二进制位
return 0;
}
为什么会有大小端
因为在计算机中,我们是以字节为单位,每一个的地址单元都对应一个地址,1个字节中有8个bite位
1.写一个代码判断机器是大端还是小端:
#include<stdio.h>
#include<string.h>
int check_says()
{
int a = 1;
#include<stdio.h>
#include<string.h>
int check_says()
{
int a = 1;
//因为前面提到了大端字节和小端字节两个存储的方式不同,一个是最低的字节数据存在低地址,另一个低字节数据存放在高地址
//我们只需要判断第一个字节如果拿出1为小端,不是1为大端
//因为int占四个字节在内存中存储
//char类型占用一个字节,强制转换为char*来访问它是否是大端还是小端
// if(*(char*)&a==1)
// return 1;
// else
// return 0;
//如果大端返回0,小端返回1
return (*(char *)&a);//因为返回只有0/1,所以可以直接将代码简化
}
int main()
{
if(check_says()==1)
printf("小端");
else
printf("大端");
//由此可见,数据在机器大部分是倒着存放的
return 0;
}
2.练习题
signed char取值的范围是-128~127
unsgined char 取值的类型范围是0~255
如果存进去的值超出类型的范围,也会转换为其范围内的值
类型的作用:
1.申请内存空间时的大小
2.类型决定了看待内存中数据的视角
#include<stdio.h>
int main()
{
char a = -1;
//10000000 00000000 00000000 00000001 -1原码
//11111111 11111111 00000000 11111110 -1反码
//11111111 11111111 00000000 11111111 -1补码
//char类型只能存放8个bite位1个字节进行截断
//11111111 a存放最低位数据
//最高位位符号位,以原来的符号位提升
//11111111 11111111 11111111 11111111 有符号整形提升高位补1 -补码a
signed char b = -1;
//11111111 b存放最低位数据的有效数字
//11111111 11111111 11111111 11111111 高位补1 -补码b
unsigned char c = -1;//unsigned 是个正数
//11111111 c存放的值二进制数列也是它
//无符号类型进行整形提升高位补0
//00000000 00000000 00000000 11111111 //高位补0 -补码c
//11111111 正数的原反补相同十进制为255
printf("a=%d,b=%d,c=%d",a,b,c);
//%d打印的是有符号的整数
//abc需要发生整形提升
//-1 ,-1,255
//%u打印的是无符号的整数
return 0;
}
3.练习题
#include<stdio.h>
int main()
{
char a = -128;
// 10000000 00000000 00000000 100000000 原
// 11111111 11111111 11111111 011111111 反码
// 11111111 11111111 11111111 100000000 补码
// 10000000 -a
printf("%u\n", a);
//%u打印的是无符号类型的数我们需要将a发生整形提升高位补1
// 11111111 111111111 111111111 10000000
//无符号的整数 原码反码 补码 相同的
char b = 128;
//char的最大类型范围为127
//000000000 00000000 00000000 10000000 原反补相同
//100000000 -b
//111111111 11111111 11111111 11111111 补码
//内存中的补码 %u认为存放的是无符号数,与a的结果相同
printf("%u\n", b);
return 0;
}
4.练习题
#include<stdio.h>
#include<string.h>
int main()
{
char a[1000];//0~999
int i;
for (int i = 0; i < 1000;i++)
{
a[i] = -1 - i;//因为char是有符号类型走到-127之后为0
//11111111+1后00000000,+1后char类型存储的值都被替换为0
//因为char需要走到-128,然后不会在负,由正数127开始循环,直到0
}
//char类型取值范围为-128~127
//char只能存8个bite位,11111111 正数没有符号位,都是有效位
//如果char为signed char 负数为100000000 为-128
//正数为01111111 为127
printf("%zu", strlen(a));//strlen当遇到第一个0停止寻找,返回结果
//127+128为255
return 0;
}
练习5
#include<stdio.h>
#include<string.h>
unsigned char i = 0;//i的取值范围为0~255
int main()
{
//循环判断的部分恒成立,会造成死循环
for (int i = 0; i <= 255;i++)
{
printf("Hello world\n");
}
return 0;
}
练习题6
#include<stdio.h>
#include<unistd.h>
int main()
{
unsigned int i;
//无符号类型i>=0
for (int i = 9; i>=0; i--)
{
printf("%d\n",i);
sleep(1);
}
//9 8 7 6 5 4 3 2 1 0 -1在无符号整数中是一个很大的数字
return 0;
}
练习题7
#include<stdio.h>
#include<unistd.h>
int main()
{
int a[4] = {1, 2, 3, 4};
int *ptr1 = (int*)(&a + 1);
int* ptr2=(int*)((int)a+1);
//a由int*类型转换为int类型+1整数+1赋给ptr2
printf("%#x,%#x", ptr1[-1], *ptr2);
//*ptr2访问四个int中的四个字节为0x02 00 00 00
return 0;
}