C 中的结构填充

问题描述 投票:0回答:6

我读过关于 C 中结构填充的文章: http://bytes.com/topic/c/answers/543879-what-struct-padding 并在文章后写了这段代码,应该打印出“struct pad”的大小,例如 16 字节,“struct pad2”的大小应该是 12。-正如我所想。 我用 gcc 编译了这段代码,并进行了不同级别的优化,甚至 sizeof() 运算符都给了我 16 个字节。 这是为什么?

此信息对我来说是必要的,因为 PS3 机器的字节边界和完整 DMA 传输的利用非常重要:

#include <stdio.h>
#include <stdlib.h>

struct pad
{
    char  c1;  // 1 byte
    short s1;  // 2 byte
    short s2;  // 2 byte
    char  c2;  // 1 byte
    long  l1;  // 4 byte
    char  c3;  // 1 byte
};

struct pad2
{
    long  l1;
    short s1;
    short s2;
    char  c1;
    char  c2;
    char  c3;
};

int main(void)
{
    struct pad P1;
    printf("%d\n", sizeof(P1));

    struct pad P2;
    printf("%d\n", sizeof(P2));

    return EXIT_SUCCESS;
}
c optimization structure
6个回答
4
投票

有两个技巧可以用来克服这个问题

  1. 使用指令

    #pragma pack(push, 1)
    ,然后使用
    #pragma pack(pop)

    示例:

    #pragma pack(push, 1)
    
    struct tight{
       short element_1;
       int *element_2;
    };
    #pragma pack(pop)
    
    struct not_tight{
       short element_1;
       int *element_2;
    };
    
  2. 要在编译期间检查两个结构的大小是否相同,请使用此技巧

     char voidstr[(sizeof(struct1)==sizeof(struct2)) - 1]; //it will return error at compile time if this fail
    

4
投票

您的结构每个都包含一个

long
,您的平台显然要求其位于四字节边界上。该结构必须至少与其最对齐的成员一样对齐,因此它必须是 4 字节对齐,并且结构的大小必须是其对齐的倍数,以防它进入数组。

需要额外的填充来使

long
对齐,因此 4 的最小倍数是 16。

两条建议:

  • 您可以通过

    计算字段的偏移量
    l1

     printf("Offset of field %s is %d\n", "l1", offsetof(struct pad, l1);
    

    要获取

    offsetof
    宏,您需要
    #include <stddef.h>
    (感谢咖啡馆!)。

  • 如果要尽可能密集地打包数据,请使用

    unsigned char[4]
    代替
    long
    ,使用
    unsigned char[2]
    代替
    short
    ,然后进行算术转换。


编辑::

sizeof(struct pad2)
12. 你的代码有一个错误;结构
P2
被声明为类型
struct pad
。试试这个:

#define xx(T) printf("sizeof(" #T ") == %d\n", sizeof(T))
  xx(struct pad);
  xx(struct pad2);

附注我绝对应该在午夜之后停止尝试回答这些问题。


1
投票

在 PS3 上,不要猜测。使用

__attribute__((aligned (16)))
或类似的。它不仅保证结构的开头将在正确的边界上对齐(如果全局或静态),还将结构填充到指定对齐的倍数。


1
投票

您的代码没有显示您认为的内容,因为 P1 和 P2 都被定义为 struct pad 的实例。 struct pad2 从未被使用过。

如果我更改 P2 的定义,使其成为 struct pad2,gcc 确实决定将其大小设为 12。


1
投票
struct pad P1;
printf("%d\n", sizeof(P1));

struct pad P2;
printf("%d\n", sizeof(P2));

P1 和 P2 具有相同的类型“struct pad”,也许您想对 P2 使用“struct pad2”。


1
投票

所有 CPU 都希望将内置数据类型(如 int、float、char、double)存储在内存中其自然边界、其长度地址处。因此,进行结构填充是为了更快地从内存访问数据。 例如, 如果声明了 int,它应该出现在内存中 4 倍地址处,如

int 的大小是 4 个字节。

类似地,对于 double,它以 8 的倍数驻留在内存中。

如果内存正确对齐,CPU 可以运行得更快并高效工作。

对于以下示例,我们假设:

Sizeof(int)=4 字节

Sizeof(float)=4字节

Sizeof(char)=1 字节

BoundsCheck

上查找详细信息
© www.soinside.com 2019 - 2024. All rights reserved.