C语言整数在内存中的存储详解

整数在内存中的存储方式:

计算机语言有很多种,但是不论是哪种语言,什么方式,何种语法写出来的程序,最终都是以二进制的形式翻译出来,交给计算机去识别和处理。

比如说,int a 和 int arr[ ],在我们创建变量或者数组,或者开辟动态内存空间时往里面放入数据,都是在向内存申请一块空间,然后把数据存入这块空间当中,那么这些数据是以什么形式来存储的呢。

下面我们来仔细剖析一下,整数在内存中是如何存储的:

比如说:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int main()
{
	int a = 10;
	return 0;
}

我们创建了一个int类型变量,并且往里面放了一个 10。

int a = 10;

首先int,在32位系平台下,C语言中int类型占4个字节,64位平台下占8个字节。

也就是说int a,就是在向内存申请了4个字节的空间大小来存储数据,而我们往a里面放了一个10,

这个10是以二进制位的方式存入a里的。

一个字节占8个bit位,所以一个int类型的变量占32个bit,一个bit位表示一个二进制数字,

而10的二进制位是 1010

那么这个 1010是怎么放入32个bit位中,上图:

 可以看到,一个二进制位占一个bit位,而10的二进制1010,占4个bit,但是一个int类型有32个bit位,当数据的二进制不够32位时,往左补0,直到够32位。而最左边的是符号位,0表示正数,1表示负数,如果是有符号的整数符号位不会参与运算,如果是无符号的整数,符号位参与运算。

综合以上逻辑,我们可以知道,如果是有符号位的int类型可以存储的最大正整数的二进制位是:

01111111 11111111 11111111 11111111

转换成10进制代表的是 2147483647

而整数在内存中存储的并不都是直接由10进制装换的二进制,存储的是数据的补码

原码:是由10进制直接转换的2进制数字

反码:符号位不变,原码按位取反

补码:反码加1

注意:(正整数的原码,反码,补码相同,原码就是反码,反码就是补码,不需要进行按位取反或者加1操作)

假设现在有一行代码:

#include<stdio.h>
int main()
{
    int a = -1;
    return 0;
}

那么这个 -1又是如何存储的。

首先,我们知道这是一个负数,是负数符号位就是1。

所以a的原码是:

10000000 00000000 00000000 00000001

原码符号位不变,其他位按位取反得到反码:

11111111 11111111 11111111 11111110

反码加1得到补码:

11111111 11111111 11111111 11111111

我们使用VS的调试来查看一下内存:

可以看到,-1在内存中显示 ff ff ff ff,这是以16进制的方式显示,我们将它转换成2进制:

 可以看到,和我们上面推测一模一样,-1在内存中存储的方式是以补码的形式存入的。

大小端的概念:

假设有一组16进制的数据:0x 11 22 33 44

那么在内存中存储的顺序是怎样的?

如果是按照顺序来存储这组数据,就是这样 11 22 33 44

我们来验证一下:

可以看到,在vs中并没有以常规顺序来存储。

这里就要解释一下大小端的问题。

什么是大小端:

小端字节存储:将数据的高位放在低地址处,低位放在高地址处

大端字节存储:将数据的低位放在低地址处,高位放在高地址处

什么叫做高位和低位:正常情况下,11 22 33 44,按照顺序来排列,11就是高位,44则是低位

而大部分的编译器都是小端存储,也就是说将数据的高位放在低地址,低位放在高地址,每一位都是以字节来分割的。

下面我们来写一个小程序来判断当前机器是大端存储还是小端存储:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int test()
{
	int i = 1;
	//取出i的地址,强制类型转换成char*类型,访问第一个字节,解引用返回去
	return *(char*)&i;
}

int main()
{
	int i = test();
	if (i == 1)
	{
		printf("小端存储\n");
	}
	else
	{
		printf("大端存储\n");
	}
	return 0;
}

 首先我们知道 1 在内存中的二进制存储方式是:

 00000000 00000000 00000000 00000001

装换成16进制:

00 00 00 01

大端存储是将数据的高位放在高地址,低位放在低地址

所以如果是大端就是这样存储的: 00 00 00 01

小端存储是将数据的高位放在低地址,低位放在高地址

所以如果是小端就是这样存储的:01 00 00 00

那我们将第一个字节的内容取出来,如果是00,就是大端,如果是01,则是小端。 

这个时候我们运用指针的知识来取出第一个字节的内容,将 i的地址取出来强制装换成 char*,就能访问到第一个字节的数据,我们直接将这个数放回取,再进行判断,如果访问的数据是01,那么返回的就是1,如果访问的数据是0,返回的就是0。返回1就是小端,返回0则是大端。

整形提升

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>


int main()
{
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;

	printf("%d\n",a);
	printf("%d\n",b);
	printf("%d\n",c);

	return 0;
}

在了解了整数在内存中的存储后,来了解一下整形提升,上述代码,a,b,c都以打印整形的方式来输出,会输出什么。

首先从a开始分析,a是有符号char类型,而char类型占1个字节,一个字节占8个bit位,a是一个负数,所以如果转换成二进制存储在内存中就是:10000001

最高位是符号位,1代表负数,符号位不变,其他位按位取反得到反码:11111110

反码加1得到补码:11111111

存储在内存中的是补码。

验证一下:

 那如果以%d的形式打印的话,%d是打印整形,而整形占4个字节,32个bit位,而a是一个char类型的变量,只占1个字节8个bit位,这个时候就会发生整形提示,符号位不变往左补齐32个bit位。

而a是一个有符号的数字,所以往左边补位会根据符号位来补齐,也就是补1:

 %d打印,是打印原码,补码减1得到反码:11111111 11111111 11111111 11111110

反码符号位不变,其他位按位取反得到原码:10000000 00000000 00000000 00000001

所以以%d的形式打印a,屏幕上会输出-1

同理,b是signed的char类型,也是有符号的数字,所以b打印的也是-1

再看到c ,c是unsigned char类型的,是一个无符号数字,他在内存中的补码也是 1111 1111

但是由于是无符号的数字,所以,符号位不会被当成符号位,而是直接参与运算,无符号在整形提升往左补位的时候,补位补的是0。

00000000 00000000 00000000 11111111 减1得到反码:

00000000 00000000 00000000 11111110 符号位不变,其他位按位取反得到原码:

01111111 11111111 11111111 00000001

%d打印原码是  255

整数的最小和最大取值范围

 这里我们拿char类型来举例:

如果是 singend char

char类型占一个字节,8个bit位,

那么他的最小取值就是 0000 0000 ,也即是0

每次加1,0000 0000  ——》1

                0000 0010   ——》2

                0000 0011   ——》3

                .....

                0111 1111     ——》127

到这里,再加1:

                1000 0000    ——》 - 128

接着加1   1000 0001    ——》 - 127

                1000 0010    ——》 - 126

                1000 0011     ——》 - 125

最后就会变成:

                ........

                1111 1110    ——》 - 2

                1111 1111     ——》-1

所以有符号的char类型的取值范围就是:-128 到 127

0111 1111是char类型正整数能取值的最大范围,加1变成 1000 0000

而在内存中的补码如果是 1000 0000 会解析被当成 -128

再加1就会变成-127,依次类推,最后会变成1111 1111,也就是负1

unsigend char的取值范围

也就是正整数的取值范围,如果是正整数,那么符号位不会被当成符号位,而是直接参与运算

所以无符号的char最小值是:0000 0000

0000 0000  ——》0

0000 0001  ——》1

0000 0010  ——》2

0000 0011  ——》3

..........

0111 1111  ——》127

1000 0000  ——》128

1000 0001  ——》129

......

1111 1111  ——》255

有符号的整数,在内存中存储,符号位不参与预算

无符号位的整数,在内存中存储胡,符号位不会被当做符号位,而是直接参与预算。

我们来验证一下char类型的取值范围是否和上述说的一样:

127的补码是 0111 1111,加一变成 1000 0000

1000 0000会被解析成-128

我们在来验证一下:

-1的补码是 1111 1111,加1变成 0000 0000

0000 0000 就是 0

以上就是整数在内存的存储详解,如果有错误的地方希望大家可以指出。 

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: "C语言指针详解.pdf" 是一份详细介绍C语言指针概念和使用的PDF文档。C语言,指针是一种特殊的变量类型,用于存储其他变量的内存地址。 该PDF文档首先详细介绍了指针的定义和声明。指针的声明需要指定指针变量的类型和名称,并使用星号(*)来表示该变量是一个指针。指针变量名的前面加上一个星号,可以获取所指向的变量的值,这被称为"解引用"。 文档还介绍了指针的运算。指针可以进行自增和自减运算,指针之间可以进行相减操作,返回的结果表示它们之间的距离或者偏移量。此外,还可以将指针赋值给另一个指针,或者将指针赋值给一个变量,反之亦然。 除了基本的指针概念,文档还详细介绍了指针的常见应用场景。这包括指针作为函数参数,用于在函数内部对传入的变量进行修改。还有通过指针来实现动态内存分配和释放,以及使用指针实现数据结构(如链表和树)等。 此外,该文档还包含一些常见的指针错误和问题的解决方案。这些错误包括空指针引用、野指针引用以及内存泄漏等。文档指出了这些错误的影响以及如何避免它们。 总的来说,"C语言指针详解.pdf" 是一份详细介绍C语言指针概念、使用和常见问题解决方案的文档,对于学习和理解C语言指针的人们是一份宝贵的资料。 ### 回答2: 《C语言指针详解.pdf》是一本关于C语言指针的详细解析的电子书。在这本书,作者详细介绍了C语言指针的概念、用途和基本语法。 首先,指针是C语言非常重要的概念,它是一种数据类型,用于存储和操作内存地址。指针可以指向各种数据类型,如整数、字符、数组和结构体等。 在《C语言指针详解.pdf》,作者详细讲解了指针的声明和初始化,以及如何通过指针来访问和修改变量的值。作者还介绍了指针与数组的关系,以及指针和函数之间的关联。 此外,书还涵盖了指针的高级应用,如指针的算术运算、指向指针的指针和指针数组等。作者通过丰富的例子和代码来帮助读者理解这些概念和技巧。 《C语言指针详解.pdf》不仅适合C语言初学者,也适合有一定编程基础的读者。通过阅读此书,读者将能够更深入地理解C语言指针的功能和用法,掌握指针在编程的灵活运用。 总之,《C语言指针详解.pdf》是一本内容详尽且易于理解的C语言指针教程。读者通过阅读此书,可以提高自己在C语言编程的指针应用能力,从而更好地实现程序的设计和开发。 ### 回答3: 《C语言指针详解.pdf》是一本介绍C语言指针概念和使用方法的详细手册。C语言的指针是一种非常重要和特殊的数据类型,它提供了直接访问内存地址的能力,使得C语言具有了更高的灵活性和效率。 这本手册首先会介绍指针的基本概念,包括指针变量的定义和声明、指针的初始化和赋值。它会详细讲解指针和变量之间的关系,以及指针的运算规则和使用方法。读者可以学习到如何通过指针操作变量的值和地址,以及如何利用指针实现函数的参数传递和返回值。 接下来,手册会介绍指针和数组之间的关系。C语言,数组名本质上是一个指向数组首元素的常量指针,因此可以通过指针来操作数组。手册将详细讲解指针和数组的指针算术运算,以及指针和多维数组的关系。 此外,手册还会介绍指针和字符串之间的关系。C语言,字符串本质上是以空字符结尾的字符数组,可以通过指针来操作字符串。手册将详细讲解指针和字符串的操作,包括字符串的输入输出、字符串的比较和拷贝。 最后,手册还会介绍指针和结构体之间的关系。C语言,结构体是用户自定义的复合数据类型,可以通过指针来操作结构体。手册将详细讲解指针和结构体的操作,包括结构体指针的定义和使用,以及结构体指针作为函数参数的传递方式。 总之,《C语言指针详解.pdf》是一本深入浅出的指针教程,对于想更深入理解C语言指针的读者来说,是一本非常实用的参考书。无论是初学者还是有一定基础的读者,都可以从获得很多宝贵的知识和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值