关于操作系统各种数据类型的内存分配的一点探讨

一、最基础的介绍(下面是关于位个字节的介绍,已经了解的可以跳过)

    为全面的记录,这里从计算机的存储开始讲起吧,计算机存储是二进制的,以位为单位,一个0或者1就是1位,而8个位是一个字节,若干个字节是一个字。

    详细如下:

        字节

        字节是指一小组相邻的二进制数码。通常是8位作为一个字节。它是构成信息的一个小单位,并作为一个整体来参加操作,比字小,是构成字的单位。

        在微型计算机中,通常用多少字节来表示存储器的存储容量。

        例如,在C++的数据类型表示中,通常char1个字节,int4个字节,double8个字节。

        理解编码的关键,是要把字符的概念和字节的概念理解准确。这两个概念容易混淆,我们在此做一下区分:

        概念描述 举例

        字符人们使用的记号,抽象意义上的一个符号。 '1' '' 'a' '$' '' ……

        字节计算机中存储数据的单元,一个8位的二进制数,是一个很具体的存储空间。0x01 0x45 0xFA……

        

        在计算机中,一串数码作为一个整体来处理或运算的,称为一个计算机字,简称字。字通常分为若干个字节(每个字节一般是8位)。在存储器中,通常每个单元存储一个字,因此每个字都是可以寻址的。字的长度用位数来表示。

        在计算机的运算器、控制器中,通常都是以字为单位进行传送的。字出现在不同的地址其含义是不相同。例如,送往控制器去的字是指令,而送往运算器去的字就是一个数。

二、基本数据类型的大小(以字节为单位,下同)

    这里计算大小的方法,我使用的是sizeof()函数,相信大家都知道,这里我作为学习的目的,对它也有详细的解释。

    sizeof是C/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数。

    首先我们列一下我们常见的数据类型吧

    整型 int    无符号整型 unsigned int    短整型 short int    无符号短整型 unsigned short int    长整形 long int

    无符号长整形  unsigned long int 字符型 char 无符号字符型 unsigned char  单精度型 float 双精度型 double

    长双精度型 long double 布尔型 bool

    代码:

    

#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
	cout.flags(ios::left);
	cout<<setw(14)<<"整型占"<<setw(4)<<sizeof(int)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"无符号整型"<<setw(4)<<sizeof(unsigned int)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"短整型"<<setw(4)<<sizeof(short int)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"无符号短整型"<<setw(4)<<sizeof(unsigned short int)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"长整型"<<setw(4)<<sizeof(long int)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"无符号长整型"<<setw(4)<<sizeof(unsigned long int)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"字符型"<<setw(4)<<sizeof(char)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"无符号字符型"<<setw(4)<<sizeof(unsigned char)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"单精度型"<<setw(4)<<sizeof(float)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"双精度型"<<setw(4)<<sizeof(double)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"长双精度型"<<setw(4)<<sizeof(long double)<<setw(4)<<"字节"<<endl;
	cout<<setw(14)<<"布尔型"<<setw(4)<<sizeof(bool)<<setw(4)<<"字节"<<endl;
	system("pause");
	return 0;
}

    输出结果:

    202234_2kR3_1589828.png

    这里我发现,加了long和没加long并没有什么不同,查了教科书,表示的范围也是相同大小,很奇怪,没有用干嘛加,百度,得知结论如下:

    加long和不加long

(1)在VC下没有区别。两种类型均用4个字节存放数据。
(2)VC是后出的编译器,之前有很多早期的C编译器,在早期编译器下long int占4个字节,int占2个字节。
(3)之所以有“整型”和“长整形”两种不同类型,是C语言在诞生时发明者规定好的,前者存储的整数的值域小于后者。
 这个问题不用牵肠挂肚,在VC下用谁都可以

三、其他类型的内存分配(指针、结构体、数组)

3.1 指针

代码:

cout<<setw(30)<<"指向整型的指针占"<<setw(4)<<sizeof(int *)<<setw(4)<<"字节"<<endl;
cout<<setw(30)<<"指向布尔型的指针占"<<setw(4)<<sizeof(bool *)<<setw(4)<<"字节"<<endl;
cout<<setw(30)<<"指向长双精度型的指针占"<<setw(4)<<sizeof(long double *)<<setw(4)<<"字节"<<endl;

结果:

203445_6Sx3_1589828.png

可以看到,这个和数据类型没有关系,其实也很简单,指针就是地址,只和操作系统的位数有关,有人奇怪,我的是64位操作系统为何是4字节应该是8字节,这是因为我的VS2010是win32平台的,我装起来就是这样,我也不知道为什么,如图:

203837_6ugU_1589828.png

3.2 数组(这里吧string看作是数组来对待)

        int a[]={1,2,3};
	char b[]="123";
	int a2[3];
	char b2[3];
	string s="a";
	string s2="a1";
	string s3="a12";
	string s4="a123456789123456789123456789123456789000000000000000000000000000000000000000000000000000000000000000";
	cout<<setw(30)<<"整型数组a[]={1,2,3};"<<setw(4)<<sizeof(a)<<setw(4)<<"字节"<<endl;
	cout<<setw(30)<<"整型数组int a2[3];"<<setw(4)<<sizeof(a2)<<setw(4)<<"字节"<<endl;
	cout<<setw(30)<<"字符型数组char b[]=\"123\""<<setw(4)<<sizeof(b)<<setw(4)<<"字节"<<endl;
	cout<<setw(30)<<"字符型数组b2[3]"<<setw(4)<<sizeof(b2)<<setw(4)<<"字节"<<endl;
	cout<<setw(30)<<"字符串string s=\"a\""<<setw(4)<<sizeof(s)<<setw(4)<<"字节"<<endl;
	cout<<setw(30)<<"字符串string s=\"a1\""<<setw(4)<<sizeof(s2)<<setw(4)<<"字节"<<endl;
	cout<<setw(30)<<"字符串string s=\"a12\""<<setw(4)<<sizeof(s3)<<setw(4)<<"字节"<<endl;
	cout<<setw(30)<<"字符串string s=\"a1234...\""<<setw(4)<<sizeof(string)<<setw(4)<<"字节"<<endl;

结果:

214727_QxBY_1589828.png

可以看到,一般的就是单个数据长度乘以数组个数。特别的对于

char b[]="123";

在末尾会有NULL终止符。

对于

        string s="a";
	string s2="a1";
	string s3="a12";
	string s4="a123456789123456789123456789123456789000000000000000000000000000000000000000000000000000000000000000";

无论你给string赋值多么长,它永远都是32个字节,与赋值是无关的,他的长度是看编译器的,我的VS2010是32,其他的可能就不是,可能是4、16等。

结构体

        /*struct test1
	{
		int a;
		char b;
	};
	struct test2
	{

		char b;
		double a;
	};
	struct test3
	{

		char b;
		test1 a;
		double c;
		char d;
		double f;
	};
	*/
	cout<<setw(60)<<"struct test1{int a;char b;}"<<setw(4)<<sizeof(test1)<<setw(4)<<"字节"<<endl;
	cout<<setw(60)<<"struct test2{char a;double b;}"<<setw(4)<<sizeof(test2)<<setw(4)<<"字节"<<endl;
	cout<<setw(60)<<"struct test3{char b;test1 b;double c;char d;double f}"<<setw(4)<<sizeof(test3)<<setw(4)<<"字节"<<endl;

结果:

224519_jCmk_1589828.png

结构体里面可不是单纯地单个数据类型大小相加减,这里面还要涉及到字节对齐,设置如下

#pragmapack(n)

n为字节对齐数,其取值为1、2、4、8、16,默认是8

并且结构体大小的计算满足如下准则:

1)

1)结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

2)结构体每个成员相对于结构体首地址的偏移量(offset)都是该成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);

3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

你可以根据这三个准则仔细推敲,我这里总结了一下,计算公式如下:

sizeof(结构体)=offsetof(最后一个元素)+sizeof(最后的元素)+sizeof(末尾填充的字节数)

其中offsetof(某元素)=min{n,sizeof(某元素)},n为设置的对齐字节数。

举个例子

对于

        struct test3
	{

		char b;
		test1 a;
		double c;
		char d;
		double f;
	};

首先看char b 它的偏移量是0,大小为1,当前大小如下

b

然后test1 a,计算结构体内的结构体时,偏移量的计算是将其打散来看,即按照a.a(即int的大小)来算偏移量,所以a的大小为8,偏移量为1,但是要被(sizeof(a.a))整除,所以偏移量为4,所以在b后加三个填充字节:

b填充字节填充字节填充字节a.aa.aa.aa.aa.ba.b
a.ba.b

(请不要在意图的比例问题,每一个小格代表一个字节)

再看double c ,他的偏移量,12,不能被8整除,填充4个字节,偏移量变成16,结果如下

b填充字节填充字节填充字节a.aa.aa.aa.aa.ba.b
a.ba.b填充字节填充字节填充字节填充字节cccc
cccc

再看char d,偏移量为24,被1整除,结果如下:

b填充字节填充字节填充字节a.aa.aa.aa.aa.ba.b
a.ba.b填充字节填充字节填充字节填充字节cccc
ccccd

再看double f ,偏移量为25,不能被8整除,加上7个填充字节,变成32,结果如下:

b填充字节填充字节填充字节a.aa.aa.aa.aa.ba.b
a.ba.b填充字节填充字节填充字节填充字节cccc
ccccd填充字节填充字节填充字节填充字节填充字节
填充字节填充字节ffffffff

最后得出sizeof(test3)=40;

套公式sizeof(test3)=offset(f)+sizeof(f)+sizeof(末尾的填充字节)

即32+8+0=40

相信看完这个例子,大家都会自己算结构体的大小了,要注意的是,offsetof(某元素)=min{n,sizeof(某元素)},n为设置的对齐字节数。而n是可以设置的!如果把n设置成2,那么sizeof(test1)=6,而不是8,读者自己去算。

顺便说一句

struct test4

{

};

sizeof(test4)=1;

四、总结

好了,相信看到这里,各位已经对内存分配的大小已经有了全新的认识,好累,第一次写博客,欢迎讨论!

转载于:https://my.oschina.net/wangbingqi/blog/471608

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值