整形数据在内存中的存储(C语言)

整形数据在内存中的存储

      • 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;
}

整形数据在内存中的存储(C语言)_第1张图片
我们可以看到对于num和num2分别存储的是补码。但是我们发现顺序有点不对劲。
这是又为什么?解下来介绍大小端

3.大小端

3.1 什么是大小端

大端(存储)模式:把一个数据的低位字节的内容,存放在高地址处,把一个数据的高位字节的内容,存放在低地址处。
大端(存储)模式:把一个数据的低位字节的内容,存放在低地址处,把一个数据的高位字节的内容,存放在高地址处。

整形数据在内存中的存储(C语言)_第2张图片

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
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
int main()
{
	unsigned int i;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
		Sleep(1);
	}
	return 0;
}

整形数据在内存中的存储(C语言)_第3张图片

此结果是无限循环,因为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. 原码 = 补码-1,然后取反;
    补充知识:原码 = 补码取反+1;
  2. 对于整形来说:数据存放内存中其实存放的是补码。

大端(存储)模式:把一个数据的低位字节的内容,存放在高地址处,把一个数据的高位字节的内容,存放在低地址处。
大端(存储)模式:把一个数据的低位字节的内容,存放在低地址处,把一个数据的高位字节的内容,存放在高地址处。

你可能感兴趣的:(c语言,开发语言)