关于结构体的内存空间使用

来源:互联网 发布:网络电视怎么看中央台 编辑:程序博客网 时间:2024/05/16 15:12

有些朋友会遇到一些面试题,关于某个结构体暂用多少内存的问题,不知道的会斩钉截铁的计算成员变量尺寸总和

菜鸟一点的直接慌了,这么简单应该暗藏杀机,我们举个例子吧

 

// sample code by cto@renshenguo.com   #include <windows.h>#include <stdio.h>typedef unsigned __int64 QWORD;//Quadruple Wordtypedef struct _CUBE{int Integer;short Short;char Char;}CUBE, *PCUBE;typedef struct _CUBER{int Integer;char Char;int Shit;}CUBER, *PCUBER;#pragma pack(1)typedef struct _IDIOT{//it idiotchar Char;int Long;short Boolean;}IDIOT, *PIDIOT;#pragma pack()typedef struct _SMART{//it's smartchar Char;int Long;short Boolean;}SMART, *PSMART;inline QWORD fnGetCycleUnit(){//rdtsc machine code__asm _emit 0x0F__asm _emit 0x31}void fnCountInterval(){QWORD qwStart;QWORD qwStop;IDIOT Idiot1;IDIOT Idiot2;SMART Smart1;SMART Smart2;DWORD dwCount;DWORD dwLoop;/* %u stand for unsigned number */qwStart = fnGetCycleUnit();Sleep(1000);/*Count how many times a second*/qwStop = fnGetCycleUnit();dwCount = qwStop - qwStart;printf("sizeof(Idiot) = %d, sizeof(Smart) = %d.\nit finshed %u times when do nothing.\n", sizeof(Idiot1), sizeof(Smart1), dwCount);/**/qwStart = fnGetCycleUnit();Idiot2.Char = Idiot1.Char;qwStop = fnGetCycleUnit();dwLoop = 0;while(qwStop - qwStart < dwCount){Idiot2.Char = Idiot1.Char;qwStop = fnGetCycleUnit();dwLoop++;}printf("It finished %u times per second when not aligned.\n", dwLoop);/**/qwStart = fnGetCycleUnit();Smart2.Char = Smart1.Char;qwStop = fnGetCycleUnit();dwLoop = 0;while(qwStop - qwStart < dwCount){Smart2.Char = Smart1.Char;qwStop = fnGetCycleUnit();dwLoop++;}printf("It finished %u times per second when aligned.\n", dwLoop);}int main(int argc, char* argv[])//ml ..  /Sc ..{CUBE Cube;CUBER Cuber;Cube.Integer = 0x12345678;Cube.Short = 0x3721;Cube.Char = 0xFF;printf("sizeof(Cube) = %d.\n", sizeof(Cube));printf("Address of Cube = %d.\n", &Cube);printf("Address of Cube.Integer = %d.\n", &Cube.Integer);printf("Address of Cube.Short = %d.\n", &Cube.Short);printf("Address of Cube.Char = %d.\n", &Cube.Char);printf("\n========there is a god damn fucking split line========\n\n");printf("sizeof(Cuber) = %d.\n", sizeof(Cuber));printf("Address of Cuber = %d.\n", &Cuber);printf("Address of Cuber.Integer = %d.\n", &Cuber.Integer);printf("Address of Cuber.Char = %d.\n", &Cuber.Char);printf("Address of Cuber.Shit = %d.\n", &Cuber.Shit);printf("\n========this is a another fucking split shit========\n\n");fnCountInterval();return 0;}


有屎以来最大的疑惑,让人大吃一斤啊!

 

sizeof(Cube) = 8.Address of Cube = 1245048.Address of Cube.Integer = 1245048.Address of Cube.Short = 1245052.Address of Cube.Char = 1245054.========there is a god damn fucking split line========sizeof(Cuber) = 12.Address of Cuber = 1245036.Address of Cuber.Integer = 1245036.Address of Cuber.Char = 1245040.Address of Cuber.Shit = 1245044.========this is a another fucking split shit========sizeof(Idiot) = 7, sizeof(Smart) = 12.it finshed 2193044238 times when do nothing.It finished 12030782 times per second when not aligned.It finished 15952404 times per second when aligned.Press any key to continue


我们先看第一条分割线以上的部分,Cube的内存大小不是7而是8,Cuber更加,不是9而是12.

数学极度牛插的你很快会发现他们都是4的倍数,莫非32位系统下按32位来分配内存?

可以这么理解,其实这是一个概念,叫内存对齐,一般开发软件几乎不需要理会它,由编译器自己去搞定,也就是术语所说的对开发人员透明.

我这里所说的,是因为有些同志不习惯用sizeof,而喜欢直接用数字,比如将Cube结构写入文件:

 

fwrite(&Cube, sizeof(Cube), 1, pf);

 

即从Cube的内存地址开始,写入1个Cube结构大小的数据到pf指针指向的文件.然而很多同志喜欢这样:

 

fwrite(&Cube, 7, 1, pf);

 

其实这样问题不太大,但如果是Cuber,那么Cuber.Integer就丢失了最高位1个字节!!!

那么,每次调用sizeof(),这个是不是函数啊?调用函数,我记得大侠你说过要push ebp什么的一堆寄存器操作,效率降低哇!

我们看看,反汇编:

看到了吧,C/C++函数的调用是从右向左依次将函数压入堆栈的,这里并没有call sizeof的痕迹,直接是8!所以并不影响程序的效率.

 

那么为什么是一定要对齐呢?那不是浪费吗?原因上面已经给出一部分了.内存对齐后程序的内存访问效率会得到提升(也有一说Pentium以后的CPU是一样的)

至少32位下(乃至64位CPU在32位系统下是这样的).上面有个函数需要解释一下:

inline QWORD fnGetCycleUnit()

当然,QWORD你知道的,最上面已经定义了是unsigned __int64,是否需要64位cpu支持,我不知道,我的是,个人觉得应该不需要.

可是,这个函数没有返回值哇???其实函数体里面的机器码是执行一条x86指令:rdtsc,因为据说内联汇编不支持,所以直接用机器码.

rdtsc会把64位的CPU振荡周期计数填充到edx和eax两个寄存器中,edx保存高32位,而正好,这两个寄存器是VC中函数返回值存放的地方,所以不需要return;

然后是,对于几个内存的访问,虽然是好几条指令,但是对于主频3.0GHz的CPU就像人的一生对于130多亿年的宇宙历史,实在是沧海一粟!

而且,这个东西稳定性很差,CPU温度,甚至你摸一下键盘都可能影响它得到的值...所以我才用N次实验取平均的统计法来计算.

结果你也看到了...

 

文章随便写写,也花很多时间和经历,随便看看,如过眼云烟.不过希望大家多用sizeof().

就这样吧

原创粉丝点击