1、整形在内存中的存储
1.1 原码、反码、补码
计算机中整数有三种二进制表示方法,分别是原码、反码、补码
三种表示方法由符号位和数值位构成,符号位用0表示正数,1表示负数。
整形数据在内存中存放的是补码
正数的原码、反码、补码相同
负数的补码=原码的符号位不变,其它位按位取反得到反码,反码+1得到补码
//10
//原码=反码=补码
//00000000 00000000 00000000 00001010
//-10
//10000000 00000000 00000000 00001010 原码
//11111111 11111111 11111111 11110101 反码
//11111111 11111111 11111111 11110110 补码
为什么整形在内存中存放的是补码?
在计算机系统中,数值一律用补码来表示和存储,原因在于使用补码,可以将符号位和数值位统一处理,同时,加法和减法也可以统一,CPU只有加法。
1.2 大小端
1.2.1 什么是大小端
大端存储模式,是指数据的高位保存在内存的低地址处,数据的低位保存在高地址处。
小端存储模式,是指数据的低位保存在内存的低地址处,数据的高位保存在高地址处。
1.2.2 为什么要有大小端
一个数据如果超过一个字节存放在内存里,有存储顺序的问题
因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应者一个字节,一个字节为8bit,但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的int型(取决于编译器)。对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么。然存在着一个如何将字节安排的问题,因此导致了大小端的存储模式。
1.2.3 大小端判断
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。
int check_sys()
{
int a = 1;
//00000000 00000000 00000000 00000001
//0x 00 00 00 01
//小端存储 01 00 00 00
//大端存储 00 00 00 01
//char* p = (char*)&a;//强制转换成char*
//char*的指针解引用可以访问一个字节
//&a 第一个字节地址保存在char*的指针中
//if (*p == 1)
//{
// return 1;//小端
//}
//else
//{
// return 0;//大端
//}
//return *p;
return *(char*)&a;//先取地址 取地址后强制类型转换成char*地址 解引用访问一个字节
}
int main()
{
int ret=check_sys();
if (ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
1.3 相关练习题
//练习1
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("a=%d,b=%d,c=%d", a, b, c);
return 0;
}
//结果 -1 -1 255
//解析
int main()
{
char a = -1;
//-1
//10000000 00000000 00000000 00000001
//11111111 11111111 11111111 11111110
//11111111 11111111 11111111 11111111 补码
// 有符号char a里存放低八个比特位
//11111111
//以%d的形式打印 打印一个整形 有符号char 不够一个整形 整形提升
//当打印a的时候要发生整形提升
//整形提升补的是原来变量的符号位
//11111111 11111111 11111111 11111111 提升之后的补码
//打印的是有符号数 补码->原码
//10000000 00000000 00000000 00000001
signed char b = -1;
unsigned char c = -1;
//-1
//10000000 00000000 00000000 00000001
//11111111 11111111 11111111 11111110
//11111111 11111111 11111111 11111111 补码
//11111111 c里存放
//c是%d的形式打印 打印一个整形 要整形提升
//c是unsigned char 高位补0
//00000000 00000000 00000000 11111111 补码
//高位是0 0是整数 原码反码补码相同
printf("a=%d,b=%d,c=%d", a, b, c);
return 0;
}
//练习2
int main()
{
char a = -128;
printf("%u\n", a);
return 0;
}
//结果 4294967168
int main()
{
char a = 128;
//-128
//10000000 000000000 00000000 100000000
//11111111 111111111 11111111 011111111
//11111111 111111111 11111111 100000000
//10000000发生截断 保留低八个比特位
//%u 指的是打印无符号整数
// 整形
//11111111 111111111 11111111 100000000
//%u 补码=原码
printf("%u\n", a);
return 0;
}
//练习3
int main()
{
char a = 128;
printf("%u\n", a);
return 0;
}
//结果 4294967168
int main()
{
char a = 128;
//128
//00000000 000000000 00000000 100000000
//10000000-a发生截断 保留低八个比特位
//按照%u打印 对a进行整形提升 指的是打印无符号整数
// 整形
//11111111 111111111 11111111 100000000
//%u 补码=原码
printf("%u\n", a);
return 0;
}
//练习4
int main()
{
int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
return 0;
}
int main()
{
int i = -20;
//-20
//100000000 00000000 00000000 00010100
//111111111 11111111 11111111 11101011
//111111111 11111111 11111111 11101100 -20的补码
unsigned int j = 10;
//10
//000000000 00000000 00000000 00001010
//-20+10
//000000000 00000000 00000000 00001010
//111111111 11111111 11111111 11101100
//111111111 11111111 11111111 11110110 补码 %d有符号整数
//111111111 11111111 11111111 11110101
//100000000 00000000 00000000 00001010
printf("%d\n", i + j);
//111111111 11111111 11111111 11110110 补码 %d有符号整数
//111111111 11111111 11111111 11110101
//100000000 00000000 00000000 00001010
return 0;
}
//练习5
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
return 0;
}
//无符号整形最小值是0 没有符号位
//9 8 7 6 5 4 3 2 1 0 -1
//-1对于无符号整形来说是32个比特位都是1
//-1
//10000000 00000000 00000000 00000001 原码
//11111111 11111111 11111111 11111110 反码
//11111111 11111111 11111111 11111111 补码
//编译器不认为补码的符号位是负数,理解成正数
//编译器按照正整数打印
//打印从9-0-4294967295-0-4294967295-0循环下去
//练习6
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
//数组a中元素
//-1 -2 -3 -128 127 126 ....3 2 1 0 -1 -2..........
strlen是求字符串长度的 找的是\0的位置,统计\0之前出现多少个字符
//'\0'的ASCII码值是0
//数组每个元素char类型的值,有符号的char表示值的范围-128-127
//值的范围是 0->127->-128->-1->0
//字符串为255个(128+127)
//练习7
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
//死循环打印hello world
//无符号的char取值范围是0-255