我是结构新手,正在学习如何找到结构的大小。我知道如何使用填充来正确对齐内存。根据我的理解,对齐完成后,内存中的大小为4的倍数。我在GCC上尝试了以下代码。
struct books{
short int number;
char name[3];
}book;
printf("%lu",sizeof(book));
最初我以为short int会占用2个字节,然后是从头开始在第三个内存位置开始的字符数组。然后,字符数组需要3个字节的填充,其大小为8.像这样,每个字代表内存中的一个字节。
简短的char char
填充填充填充垫
但是在运行时它的大小为6,这让我很困惑。
任何帮助将不胜感激,谢谢!
通常,插入填充以允许对齐结构的内部元件,不允许整个结构为多个单词的大小。对齐是编译器实现问题,而不是C标准的要求。
因此,长度为3个字节的char元素不需要对齐,因为它们是字节元素。
尽管不是必需的,但优选短元素需要在短边界上对齐 - 这意味着偶数地址。通过将其对齐在短边界上,编译器可以发出单个加载短指令,而不必加载字,掩码,然后移位。
在这种情况下,填充可能(但不一定)发生在结束而不是中间。您必须编写代码来转储元素的地址以确定填充的位置。
编辑:。正如@Euguen Sh所提到的,即使你发现了编译器用于结构的填充方案,编译器也可以在不同版本的编译器中修改它。
依靠编译器的填充方案是不明智的。总是存在以这样的方式访问元素的方法,即您不会猜测对齐。
sizeof()运算符用于允许您查看使用了多少内存,并且如果该指针递增1(ptr ++),则可以知道将ptr添加到结构中的数量。
编辑2,包装:可以使用__packed__
属性打包结构以防止填充。在设计结构时,使用自然包装的元素是明智的。在通过通信链路发送数据时,这一点尤为重要。精心设计的结构避免了在结构中间填充的需要。设计不良的结构然后使用__packed__
属性编译可能具有不自然对齐的内部元素。人们可能会这样做,以确保结构将像最初设计的那样通过电线传输。随着JSON的引入,通过线路传输数据,这种努力已经减少。
#include <stdalign.h>
#include <assert.h>
结构的大小总是可以被成员的最大对齐(它必须是2的幂)整除。如果你有一个char
和short
的结构,那么对齐是2,因为short
的对齐是2,如果你有一个结构,只有char
s它的对齐为1。
有多种方法可以操纵对齐方式:
alignas(4) char[4]; // this can hold 32-bit ints
这是非标准的,但在大多数编译器(GCC,Clang,...)中都可用:
struct A {
char a;
short b;
};
struct __attribute__((packed)) B {
char a;
short b;
};
static_assert(sizeof(struct A) == 4);
static_assert(alignof(struct A) == 2);
static_assert(sizeof(struct B) == 3);
static_assert(alignof(struct B) == 1);
通常编译器遵循目标体系结构的ABI。它定义了结构和原始数据类型的对齐。这会影响所需的填充和结构尺寸。因为在许多架构中对齐是4的倍数,所以结构的大小也是如此。
编译器可以提供一些属性/选项,用于或多或少地直接改变对齐。
例如gcc和clang提供:__attribute__ ((packed))