一文轻松理解内存对齐(2)

本文涉及的产品
.cn 域名,1个 12个月
简介: 一文轻松理解内存对齐

有效对齐值为2字节


例子


请写出以下代码的输出结果:


#include<stdio.h>
struct S1
{
    int i:8;    
    char j:4;  
    int a:4;  
    double b;
};
struct S2
{
    int i:8;    
    char j:4;  
    double b;
    int a:4;  
};
struct S3
{
    int i;    
    char j;  
    double b;
    int a;     
};
int main()
{
    printf("%d\n",sizeof(S1));  // 输出8
    printf("%d\n",sizeof(S1);  // 输出12
    printf("%d\n",sizeof(Test3));  // 输出8
    return 0;
}

分析问题


在存储某些数据时,其实际需求的数据长度可能要小于一个字节,只占一位或几位。为了节省空间,处理方便,在C中引入了另一种结构,称为“位域”或“位段”。


所谓“位域”,就是把一个字节中的“位”按照实际的需求分成不同的区域,表明每个区域位数、区域的域名,并允许程序按照域名进行操作。如此就可以把不同的对象用一个字节来表示。


位域的定义与结构定义相仿,其形式为:


struct 位域的结构体名

{

  //位域列表

}

位域列表的形式为:【类型说明符】 【位域名】:【位域的长度】例如:


struct ab
{
   int a:8;
   int b:2;
   int c:6;
}

对于位域的定义,有以下几点说明:


(1)一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。


例如:


struct wy
{
   unsigned a:6;
   unsigned 0;     //空域
   unsigned b:4;   //从一单元开始存放
   unsigned c:4;   
}

在这个位域定义中,a占第一字节的6位,后2位填0表示不使用,b从第二字节开始,占用4位,c占用4位。内存结构如下图所示。




存储结构图


(2)由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是不能超过8位二进位。


(3)位域可以无位域名,这时它只用来填充或调整位置。无名的位域是不能使用的。


例如:


struct wk
{
   int a:1;
   int :2;     //不能使用
   int b:3;  
   int c:2;   
}


存储结构图


从以上述分析可以看出,位域可以看做是一种结构类型,其特点是成员均按二进位分配。


根据以上分析可知,在s1中i在相对0的位置,占8位即第1个字节。j就在相对第2个字节的位置。由于一个位置的字节数是4位的倍数,因此不用对齐,可以就放在那里。a要放在4位倍数关系的位置上,因此不用对齐,就放在那里。


目前总共是16位,2字节,由于double是8字节的,因此要在距相对0位置为8个字节的位置处放下。所以从16位开始到8个字节之间的位置被忽略,直接放在相对第8字节的位置,因此,s1总共占16字节。存储结构如下图所示。




S1存储结构


在s2中,每个数据都要对照结构体内最大数据的最小公倍数补齐。如i,j共12位,小于double的8个字节需按8字节补齐,a位也要按8字节补齐,共24个字节,存储结构如下图所示。




s2的存储结构


在s3中,i是int型数据(按32位机分析)占4个字节,j是char型数据占一个字节,a是int型数据占4个字节,b是double型数据占8个字节。 在此b是最大的数据类型,因此i、j、a都要向b的double型对齐,即i、j、a的数据长度要向b对齐为8个字节,四个数据共占据32个字节。s3的存储结构如下图所示。




s3的存储结构


答案


sizeof(S1)=16


sizeof(S2)=24


sizeof(S3)=32


说明:结构体作为一种复合数据类型,其构成元素既可以是基本数据类型的变量,也可以是一些复合型类型数据。对此,编译器会自动进行成员变量的对齐以提高运算效率。默认情况下,按自然对齐条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同,向结构体成员中size最大的成员对齐。


许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,而这个k则被称为该数据类型的对齐模数。

相关文章
|
7月前
|
编译器 Linux C语言
结构体内存对齐
结构体内存对齐
61 0
|
7月前
|
存储 编译器 C语言
结构体的内存对齐与位段
当我们描述一个人的年龄时我们可以使用,int age = 18;但是如果我们要描述一个人呢?很显然我们无法仅靠一个age就实现对一个人的描述,所以就有了结构体,在结构体中我们可以包含多种类型的数据,这样就可以实现对一个人的描述比如身高、爱好、体重等等
|
存储 编译器 C语言
关于内存对齐
关于内存对齐
133 0
|
编译器 Linux C++
C/C++中内存对齐的问题的讲解
C/C++中内存对齐的问题的讲解
169 0
|
编译器 C++
【关于结构体内存对齐问题】(上)
【关于结构体内存对齐问题】
122 0
|
C++
【关于结构体内存对齐问题】(下)
【关于结构体内存对齐问题】
106 0
|
编译器 Linux C语言
结构体的内存对齐与位段的实现
注意上面这两种结构体都是属于匿名结构体类型,不告诉你名字,这种结构体类型如果要使用必须在声明的时候就在后面定义变量,不能再到主函数里面引用,因为你不知道这个结构体的名字是什么,所以必须在声明的时候就定义变量。
93 0
|
编译器 C++
什么是结构体内存对齐,位段
什么是结构体内存对齐,位段
116 0
什么是结构体内存对齐,位段
|
编译器 C++
结构体内存对齐,位段
结构体内存对齐,位段
108 0
结构体内存对齐,位段