结构体(或者联合体)变量的成员在内存里是如何分布的

本文深入探讨了结构体成员在内存中的分布规律,包括对齐原则、成员间内存分布及特殊成员处理,揭示了编译器如何优化内存访问效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

结构体(或者联合体)变量的成员在内存里是如何分布的

1.概述

结构体变量的成员在内存里是如何分布的、成员先后顺序是怎样的、成员之间是连续的还是分散的、还是其他的什么形式?这些问题既和软件相关又和硬件相关。所谓软件相关主要是指和具体的编程语言的编译器的特性相关,编译器为了优化CPU访问内存的效率,在生成结构体成员的起始地址时遵循着某种特定的规则,这就是所谓的 结构体成员“对齐”;所谓硬件相关主要是指CPU的“字节序”问题,也就是大于一个字节类型的数据如int类型、short类型等,在内存中的存放顺序,即单个字节与高低地址的对应关系。

2.分布规则

(1)为了提高CPU访问内存的效率,程序语言的编译器在做变量的存储分配时进行了优化处理,处理的原则是:对于n字节的元素,它的首地址能被n整除,这种原则称为“对齐”。

(2)结构体(联合体)的成员所占内存地址依次增高,第一个成员位于低地址处,最后一个成员位于高地址处,但是结构体成员的内存并不是连续的,编译器会对成员做上述“对齐”处理。

(3)通常编译器可以设置一个对齐参数n,结构体中每个成员实际对齐参数N根据N=min(sizeof(成员类型),n)来得到。结构体成员的内存偏移地址x,满足条件x%N=0。

(4)结构体所有成员的对齐参数N的最大值称为结构体的对齐参数。整个结构的长度必须是结构体对齐参数的最小整数倍,不够补0。

简单来说:

1)结构体的起始地址为x,x%sizeof(结构体)=0。

2)结构体每个成员相对于起始地址偏移地址y,y%N=0。

3)结构体长度等于结构体对齐参数的最小整数倍。

注:编译器对齐参数可以通过指令控制,例如#param pack(2)两字节对齐。vs2010IDE还可以通过"项目属性"->"C/C++"->"代码生成"->“结构成员对齐”来设置。编译器默认对齐参数为8个字节。

例:

复制代码

struct A
{
    char      c;   //1byte
    double    d;   //8byte
    short     s;   //2byte
    int       i;   //4byte
};
int main(int argc, char*argv[])
{
    A strua;
    printf("len:%d\n",sizeof(A));
    printf("%d,%d,%d,%d",&strua.c,&strua.d,&strua.s,&strua.i);
    return 0;
}

复制代码

输出结果为:
len:24
1506156,1506164,1506172,1506176

3.特殊成员

(1)结构体成员为数组时,是将数组的每个元素当一个成员来分配,并不是将整个数组当成一个成员来对待。其他成员的分配规则按照上述规则。

(2)当结构体成员是位段时,存储是按其类型分配空间的,如int型的位段就分配4个字节的存储单元。相邻的同类型的两个位段,如果该类型的长度够用,就将两位段连续存放,共用存储单元,如果不够用,就另起一个该类型长度的存储空间。相邻的不同类型的两个位段,分别为这两个位段分配它们所属类型长度的存储空间。其他成员的分配规则按照上述规则。

1)例1:

复制代码

struct bit  
{  
    int a:3;
    int b:2;
    int c:3;
};
int main(int argc,char* argv[])    
{    
    bit s;    
    char *c = (char*)&s;    
    *c = 0x99;    
    cout<<s.a<<endl<<s.b<<endl<<s.c<<endl;  
    return 0;    
}

复制代码

输出结果:  1   -1   -4  

分析:

hex    0x99

bin    100  11   001

            c      b       a

地址   高   -->     低

cpu为小端模式,高位比特存储在高地址中,低位比特存储在低地址中。而且计算机中存储的是数的补码形式。

2)例2:

复制代码

struct   bit  
{  
    char   a:5;
    char   b:4;
    char   c:7;
};
int main(int argc,char* argv[])    
{    
    bit s;    
    int *c = (int*)&s;    
    *c = 0x99E00000;    
    cout<<sizeof(bit)<<endl<<(int)s.a<<endl<<(int)s.b<<endl<<(int)s.c<<endl;  
    return   0;    
}

复制代码

输出结果:3 0 0 -32

hex    0x99          0xE0         0x00           0x00

bin   10011001  11100000  00000000  00000000

 

                                  c                   b                a

 

地址      高                    -->                       低

 

结构体的定义和访问结构体成员结构体是由一组不同类型的变量组成的数据类型,可以通过定义一个结构体变量来使用结构体,访问结构体成员使用"."操作符,例如: ``` struct Person { char name[20]; int age; float height; }; Person p; strcpy(p.name, "Tom"); p.age = 20; p.height = 1.75; ``` 以上代码定义了一个Person结构体,包含了char类型的name、int类型的age和float类型的height三个成员变量,然后定义了一个Person类型的变量p,使用strcpy函数给p.name赋值,给p.age和p.height赋值。 联合体的定义和访问联合体成员联合体是一种数据类型,它允许在同一内存位置存储不同的数据类型。联合体的定义方式与结构体相似,但是联合体中的成员变量共享同一块内存空间,因此联合体中只能同时存储一个成员变量的值,访问联合体成员使用"."操作符,例如: ``` union Data { int i; float f; char str[20]; }; Data d; d.i = 10; cout << d.i << endl; // 输出10 d.f = 3.14; cout << d.f << endl; // 输出3.14 strcpy(d.str, "hello"); cout << d.str << endl; // 输出hello ``` 以上代码定义了一个Data联合体,包含了int类型的i、float类型的f和char类型的str三个成员变量,然后定义了一个Data类型的变量d,首先给d.i赋值,然后给d.f赋值,最后使用strcpy函数给d.str赋值。由于联合体中的成员变量共享同一块内存空间,因此d.i和d.f的值会互相覆盖,最后输出d.str时,输出的是d.str中存储的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值