结构的大小如何是4的非倍数?

问题描述 投票:1回答:3

我是结构新手,正在学习如何找到结构的大小。我知道如何使用填充来正确对齐内存。根据我的理解,对齐完成后,内存中的大小为4的倍数。我在GCC上尝试了以下代码。

struct books{
  short int number;
  char name[3];
}book;
printf("%lu",sizeof(book));

最初我以为short int会占用2个字节,然后是从头开始在第三个内存位置开始的字符数组。然后,字符数组需要3个字节的填充,其大小为8.像这样,每个字代表内存中的一个字节。

简短的char char

填充填充填充垫

但是在运行时它的大小为6,这让我很困惑。

任何帮助将不胜感激,谢谢!

c struct sizeof
3个回答
4
投票

通常,插入填充以允许对齐结构的内部元件,不允许整个结构为多个单词的大小。对齐是编译器实现问题,而不是C标准的要求。

因此,长度为3个字节的char元素不需要对齐,因为它们是字节元素。

尽管不是必需的,但优选短元素需要在短边界上对齐 - 这意味着偶数地址。通过将其对齐在短边界上,编译器可以发出单个加载短指令,而不必加载字,掩码,然后移位。

在这种情况下,填充可能(但不一定)发生在结束而不是中间。您必须编写代码来转储元素的地址以确定填充的位置。

编辑:。正如@Euguen Sh所提到的,即使你发现了编译器用于结构的填充方案,编译器也可以在不同版本的编译器中修改它。

依靠编译器的填充方案是不明智的。总是存在以这样的方式访问元素的方法,即您不会猜测对齐。

sizeof()运算符用于允许您查看使用了多少内存,并且如果该指针递增1(ptr ++),则可以知道将ptr添加到结构中的数量。

编辑2,包装:可以使用__packed__属性打包结构以防止填充。在设计结构时,使用自然包装的元素是明智的。在通过通信链路发送数据时,这一点尤为重要。精心设计的结构避免了在结构中间填充的需要。设计不良的结构然后使用__packed__属性编译可能具有不自然对齐的内部元素。人们可能会这样做,以确保结构将像最初设计的那样通过电线传输。随着JSON的引入,通过线路传输数据,这种努力已经减少。


2
投票
#include <stdalign.h>
#include <assert.h>

结构的大小总是可以被成员的最大对齐(它必须是2的幂)整除。如果你有一个charshort的结构,那么对齐是2,因为short的对齐是2,如果你有一个结构,只有chars它的对齐为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);

0
投票

通常编译器遵循目标体系结构的ABI。它定义了结构和原始数据类型的对齐。这会影响所需的填充和结构尺寸。因为在许多架构中对齐是4的倍数,所以结构的大小也是如此。

编译器可以提供一些属性/选项,用于或多或少地直接改变对齐。

例如gcc和clang提供:__attribute__ ((packed))

© www.soinside.com 2019 - 2024. All rights reserved.