📅  最后修改于: 2020-10-22 06:58:31             🧑  作者: Mango
结构填充是C语言中的一个概念,它在内存地址之间添加一个或多个空字节以对齐内存中的数据。
让我们首先通过一个简单的场景了解C中的结构填充,如下所示:
假设我们创建了一个用户定义的结构。当我们创建这种结构的对象时,连续内存将分配给该结构成员。
struct student
{
char a;
char b;
int c;
} stud1;
在上面的示例中,我们创建了Student类型的结构。我们已将该结构的对象声明为“ stud1″。创建对象后,将连续的内存块分配给其结构成员。首先,将内存分配给“ a”变量,然后分配给“ b”变量,然后分配给“ c”变量。
现在,我们计算结构学生的大小。我们假设int的大小为4个字节,而char的大小为1个字节。
struct student
{
char a; // 1 byte
char b; // 1 byte
int c; // 4 bytes
}
在上述情况下,当我们计算结构学生的大小时,大小为6个字节。但是这个答案是错误的。现在,我们将理解为什么这个答案是错误的?我们需要了解结构填充的概念。
处理器一次不读取1个字节。它一次读取1个字。
1个字是什么意思?
如果我们有一个32位处理器,则处理器一次读取4个字节,这意味着1个字等于4个字节。
1 word = 4 bytes
如果我们有64位处理器,则处理器一次读取8个字节,这意味着1个字等于8个字节。
1 word = 8 bytes
因此,可以说32位处理器一次可以访问4个字节,而64位处理器一次可以访问8个字节。取决于体系结构,单词的大小将是多少。
struct student
{
char a; // 1 byte
char b; // 1 byte
int c; // 4 bytes
}
如果我们有一个32位处理器(一次4个字节),则上述结构的内存的图形表示为:
如我们所知,结构占用了上图所示的连续内存块,即char a为1个字节,char b为1个字节,int c为4个字节,那么在这种情况下我们要面对什么问题。
考虑使用32位架构时,一次可以访问4个字节。问题在于,在一个CPU周期中,可以访问char a的一个字节,char b的一个字节和int c的2个字节。访问char a和char b时不会遇到任何问题,因为两个变量都可以在一个CPU周期中访问,但是当我们访问int c变量时将面临问题,因为需要2个CPU周期才能访问value。 ‘c’变量。在第一个CPU周期中,访问前两个字节,在第二个周期中,访问其他两个字节。
假设我们不想访问’a’和’b’变量,我们只想访问变量’c’,这需要两个周期。变量“ c”为4个字节,因此也可以在一个周期内访问它,但是在这种情况下,它使用2个周期。这是不必要的CPU周期浪费。由于这个原因,引入了结构填充概念以节省CPU周期数。结构填充由编译器自动完成。现在,我们将看到如何完成结构填充。
为了实现结构填充,如上图所示,在左侧创建了一个空行,并将左侧’c’变量占用的两个字节向右移动。因此,’c’变量的所有四个字节都在右侧。现在,可以在单个CPU周期中访问’c’变量。在进行结构填充之后,结构占用的总内存为8个字节(1个字节+ 1个字节+2个字节+4个字节),大于前一个字节。尽管在这种情况下会浪费内存,但是可以在单个周期内访问变量。
让我们创建一个简单的结构程序。
#include
struct student
{
char a;
char b;
int c;
};
int main()
{
struct student stud1; // variable declaration of the student type..
// Displaying the size of the structure student.
printf("The size of the student structure is %d", sizeof(stud1));
return 0;
}
在上面的代码中,我们创建了一个名为“ student”的结构。在main()方法内部,我们声明一个学生类型的变量,即stud1,然后使用sizeof()运算符计算学生的大小。由于结构填充的概念,输出将为8个字节,我们已经在上面进行了讨论。
输出量
现在,我们将看到更改变量顺序时会发生什么,它是否影响程序的输出。让我们考虑相同的程序。
#include
struct student
{
char a;
int b;
char c;
};
int main()
{
struct student stud1; // variable declaration of the student type..
// Displaying the size of the structure student.
printf("The size of the student structure is %d", sizeof(stud1));
return 0;
}
上面的代码与先前的代码相似;我们唯一改变的是结构学生内部变量的顺序。由于顺序的变化,两种情况下的输出都会不同。在前一种情况下,输出为8个字节,但是在这种情况下,输出为12个字节,如下面的屏幕截图所示。
输出量
现在,我们需要了解“为什么在这种情况下输出会有所不同”。
结构填充是编译器自动完成的内置过程。有时需要避免使用C中的结构填充,因为这会使结构的大小大于结构成员的大小。
我们可以通过两种方式避免在C中进行结构填充:
使用#pragma pack(1)指令
#include
#pragma pack(1)
struct base
{
int a;
char b;
double c;
};
int main()
{
struct base var; // variable declaration of type base
// Displaying the size of the structure base
printf("The size of the var is : %d", sizeof(var));
return 0;
}
在上面的代码中,我们使用了#pragma pack(1)指令来避免结构填充。如果我们不使用此指令,那么上面程序的输出将是16个字节。但是结构成员的实际大小为13个字节,因此浪费了3个字节。为了避免浪费内存,我们使用#pragma pack(1)伪指令提供1字节的包装。
输出量
#include
struct base
{
int a;
char b;
double c;
}__attribute__((packed)); ;
int main()
{
struct base var; // variable declaration of type base
// Displaying the size of the structure base
printf("The size of the var is : %d", sizeof(var));
return 0;
}
输出量