您的位置:首页 > 其它

VS2010 C各类型变量在内存中的存放研究

2016-11-16 18:20 155 查看
这边文章主要用于研究各种数据类型的变量,如char,int变量,数组在内存中的存储方式,同时探讨下windows系统内存存放方式。

1.内存地址排列

测试目的:测试stack内存中局部变量存放时地址是由大到小还是由小到大。
测试方法:定义一组 char,int等数据类型变量,同时定义数组,查看内存地址。
测试代码如下:

 void stack_var_mem_test(void)

{

char cVar1=0,cVar2=0;

short sVar1=0,sVar2=0;

int iVar1=0,iVar2=0;

long lVar1=0,lVar2=0;

long long llVar1=0,llVar2=0;

printf("stack_var_mem_test\n");

printf("char mem addr : %8x, %8x\n",&cVar1,&cVar2);

printf("short mem addr : %8x, %8x\n",&sVar1,&sVar2);

printf("Int mem addr : %8x, %8x\n",&iVar1,&iVar2);

printf("long mem addr : %8x, %8x\n",&lVar1,&lVar2);

printf("long long mem addr : %8x, %8x\n",&llVar1,&llVar2);

}

void stack_var_array_mem_test(void)

{

char cVar_array[10];

short sVar_array[10];

int iVar_array[10];

long lVar_array[10];

long long llVar_array[10];

printf("stack_var_array_mem_test\n");

printf("char array mem addr: %8x, %8x\n",&cVar_array[0],&cVar_array[9]);

printf("short array mem addr: %8x, %8x\n",&sVar_array[0],&sVar_array[9]);

printf("int array mem addr: %8x, %8x\n",&iVar_array[0],&iVar_array[9]);

printf("long array mem addr: %8x, %8x\n",&lVar_array[0],&lVar_array[9]);

printf("longlong array mem addr: %8x, %8x\n",&llVar_array[0],&llVar_array[9]);

}

输出结果如下:

typeaddr1addr2size-1
char40f7e740f7db12(C)
short40f7cc40f7c012(C)
int40f7b440f7a812(C)
long40f79c40f79012(C)
long long40f78040f77016(10)
arrayaddr0addr9 
char40f7d840f7e19
short40f7bc40f7ce18
int40f78c40f7b036
long40f75c40f78036
long long40f70440f74c72
从上表中可以看到
1.局部变量在内存中是存放在栈空间中,存放方式是从高地址往低地址走,即栈顶指针指向低地址,具有先进先出的特点。
2.数组变量按照下标,首地址存放于低地址中,尾地址存放于高地址中,存放方式是从低地址往高地址走。
3.char变量一个字节,short变量2个字节,int和long变量4个字节,longlong变量8个字节。

以上测试方法存在一个问题,未考虑到大小端模式对数据在栈空间存放的影响。

2.大小端模式对各个类型变量的影响

大端模式:数据的高字节存放于低地址中。
小端模式:数据的高字节存放于高地址中。
直观的表示如下:
定义 
union Ta{
    int a;
   char b[4];
} gua;
  gua.a = 0x12345678;
gua.b[0]~gua.b[4]的值则如下:

typeaddrmodebig-edionlittle-edion
b0d11278
b1d2 3456
b2d3 5634
b4d4 7812
1.数组在内存中存放的方式是从低地址到高地址。
2.存放于内存中的变量(short,int..)存放方式根据系统的大小端模式而定。
3.对于多维数组而言,数据按照下标顺序从低地址到高地址顺序存放。

3.结构体内存排列方式

 结构体对齐原因有很大部分是因为计算机扫描的内存单元个数,也就是数据总线的大小。

    原则1:数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。

    原则2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)

    原则3:收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。

    这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。

    例1:struct{

                 short a1;

                 short a2;

                 short a3;

                 }A;

         struct{

                 long a1;

                 short a2;

                 }B;

         sizeof(A) = 6; 这个很好理解,三个short都为2。

         sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,整个为8,因为原则3。

    例2:struct A{

                 int a;

                 char b;

                 short c;

                 };

         struct B{

                 char b;

                 int a;

                 short c;

                 };

         sizeof(A) = 8; int为4,char为1,short为2,这里用到了原则1和原则3。

         sizeof(B) = 12; 是否超出预想范围?char为1,int为4,short为2,怎么会是12?还是原则1和原则3。

    深究一下,为什么是这样,我们可以看看内存里的布局情况。

                       a         b       c

         A的内存布局:1111,     1*,      11

                       b         a       c

         B的内存布局:1***,     1111,   11**

    其中星号*表示填充的字节。A中,b后面为何要补充一个字节?因为c为short,其起始位置要为2的倍数,就是原则1。c的后面没有补充,因为b和c正好占用4个字节,整个A占用空间为4的倍数,也就是最大成员int类型的倍数,所以不用补充。

    B中,b是char为1,b后面补充了3个字节,因为a是int为4,根据原则1,起始位置要为4的倍数,所以b后面要补充3个字节。c后面补充两个字节,根据原则3,整个B占用空间要为4的倍数,c后面不补充,整个B的空间为10,不符,所以要补充2个字节。

    再看一个结构中含有结构成员的例子:

    例3:struct A{

                 int a;

                 double b;

                 float c;

                 };

         struct B{

                 char e[2];

                 int f;

                 double g;

                 short h;

                 struct A i;

                 };

         sizeof(A) = 24; 这个比较好理解,int为4,double为8,float为4,总长为8的倍数,补齐,所以整个A为24。

         sizeof(B) = 48; 看看B的内存布局。

                       e      f       g           h                         i 

         B的内存布局:11* *, 1111, 11111111, 11 * * * * * *,1111* * * *, 11111111, 1111 * * * *

    考虑一个问题,为什么要设计内存对齐的处理方式呢?如果体系结构是不对齐的,成员将会一个挨一个存储,显然对齐更浪费了空间。那么为什么要使用对齐呢?体 系结构的对齐和不对齐,是在时间和空间上的一个权衡。对齐节省了时间。假设一个体系结构的字长为w,那么它同时就假设了在这种体系结构上对宽度为w的数据 的处理最频繁也是最重要的。它的设计也是从优先提高对w位数据操作的效率来考虑的。有兴趣的可以google一下,人家就可以跟你解释的,一大堆的道理。

    最后顺便提一点,在设计结构体的时候,一般会尊照一个习惯,就是把占用空间小的类型排在前面,占用空间大的类型排在后面,这样可以相对节约一些对齐空间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐