整形数据在内存中的存储
- 1.整形家族
- 2.(原码、反码、补码)基础知识
- 3.大小端
- 3.1 什么是大小端
- 3.2 为什么有大端和小端
- 3.3 一道关于大小端字节序的面试题
- 3.4 关于整形数据存储的题目(7题)
- 3.4.1
- 3.4.2
- 3.4.3
- 3.4.4
- 3.4.5
- 3.4.6
- 3.4.7
- 4.总结
1.整形家族
signed可省可不省,一般省略不写
unsigned char
signed char
unsigned short [int]
signed short [int]
unsigned int
signed int
unsigned long [int]
signed long [int]
2.(原码、反码、补码)基础知识
计算机中的整数有三种2进制表示方法,即原码、反码和补码。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”。
正数的原、反、补码都相同。
负整数的三种表示方法各不相同。
- 原码
直接将数值按照正负数的形式翻译成二进制就可以得到原码。 - 反码
将原码的符号位不变,其他位依次按位取反就可以得到反码。 - 补码
反码+1就得到补码。
对于整形来说:数据存放内存中其实存放的是补码。
原因在于:在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;
同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
int main()
{
//为了方便表示,在vs中数据以十六进制呈现出来
//0x0000000a ->10
int num = 10;
//0xfffffff6 ->-10
int num2 = -10;
}
我们可以看到对于num和num2分别存储的是补码。但是我们发现顺序有点不对劲。
这是又为什么?解下来介绍大小端
3.大小端
3.1 什么是大小端
大端(存储)模式:把一个数据的低位字节的内容,存放在高地址处,把一个数据的高位字节的内容,存放在低地址处。
大端(存储)模式:把一个数据的低位字节的内容,存放在低地址处,把一个数据的高位字节的内容,存放在高地址处。
3.2 为什么有大端和小端
因为在计算机系统中,是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8 bit。但是在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
3.3 一道关于大小端字节序的面试题
设计一个小程序来判断当前机器的字节序。
#include<stdio.h>
int check_sys1()
{
int a = 1;
return (*(char*)&a);
}
//方法2
int check_sys2()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c;
}
int main()
{
int ret = check_sys1();
if (ret == 1)
printf("小端字节序存储\n");
else
printf("大端字节序存储\n");
printf("%d", ret);
}
3.4 关于整形数据存储的题目(7题)
原码 = 补码-1,然后取反
补充知识:原码 = 补码取反+1
3.4.1
int main()
{
char a = -1; //char是有符号字符类型,并且取值范围能存下-1,因此打印-1
//10000000 00000000 00000000 00000001 原码
//11111111 11111111 11111111 11111110 反码
//11111111 11111111 11111111 11111111 补码
//11111111 -a 截断(因为char只有1字节=8bit)
//%d整形打印: 先提升,然后将补码转换成原码
//11111111 11111111 11111111 11111111 补码
//10000000 00000000 00000000 00000000 反码
//10000000 00000000 00000000 00000001 原码 ->-1
signed char b = -1; //char 和 signed char是一样的,知识char默认为有符号,所以省略了signed,结果也是-1
//b同a一样
unsigned char c = -1; //此时char是无符号
//00000000 00000000 00000000 11111111 补码
//11111111 -c 截断,因为是无符号,所以整形提升时前面补0
//%d打印:需要发生整形提升
//00000000 00000000 00000000 11111111 ->255
printf("a=%d,b=%d,c=%d", a, b, c);
return 0;
}
3.4.2
int main()
{
char a = -128;
//10000000 00000000 00000000 10000000 原码
//11111111 11111111 11111111 01111111 反码
//11111111 11111111 11111111 10000000 补码
//10000000 ->-128
//按%u: 无符号整形打印,需整形提升
//11111111 11111111 11111111 10000000 ->4294967168
printf("%u\n", a);
return 0;
}
3.4.3
int main()
{
char a = 128;
//10000000 00000000 00000000 10000000 原码 ->整形提升
//11111111 11111111 11111111 01111111 反码
//11111111 11111111 11111111 10000000 补码
//10000000 ->128
//按%u: 无符号整形打印,需整形提升
//11111111 11111111 11111111 10000000 ->4294967168
printf("%u\n", a);
return 0;
}
3.4.4
int main()
{
int i = -20;
//10000000 00000000 00000000 00010100
//11111111 11111111 11111111 11101011
//11111111 11111111 11111111 11101100 ->补码
unsigned int j = 10;
//00000000 00000000 00000000 00001010 ->补码
//11111111 11111111 11111111 11101100 +
//11111111 11111111 11111111 11110110 ->补码
//10000000 00000000 00000000 00001001
//10000000 00000000 00000000 00001010 ->10
printf("%d\n", i + j);
return 0;
}
3.4.5
#include<windows.h>
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
Sleep(1);
}
return 0;
}
此结果是无限循环,因为i是无符号整形,i的值只可能大于等于0;
3.4.6
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
//-1 -2 -3 -4....-128 127 126 125... 0
//-1 -2 -3 -4....-128 127 126 125... 0
//...
strlen遇到\0就结束,并且\0 == 0的,因此在第一次遇到0时就结束计算;
结果是:128+127=255, 不包括\0;
3.4.7
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
因为i是无符号字符型,并且i<=255,当i=255时,此时i++的结果是0,因此导致程序死循环;
4.总结
- 正数的原、反、补码都相同。
负整数的三种表示方法各不相同。
- 原码
直接将数值按照正负数的形式翻译成二进制就可以得到原码。 - 反码
将原码的符号位不变,其他位依次按位取反就可以得到反码。 - 补码
反码+1就得到补码。
- 原码 = 补码-1,然后取反;
补充知识:原码 = 补码取反+1; - 对于整形来说:数据存放内存中其实存放的是补码。
大端(存储)模式:把一个数据的低位字节的内容,存放在高地址处,把一个数据的高位字节的内容,存放在低地址处。
大端(存储)模式:把一个数据的低位字节的内容,存放在低地址处,把一个数据的高位字节的内容,存放在高地址处。