【问题标题】:Aligning memory address of specific pragma packed struct member?对齐特定编译指示压缩结构成员的内存地址?
【发布时间】:2014-12-24 21:18:57
【问题描述】:

我有一个结构,其中包含不同长度类型的数据成员(一些整数,一些单词,一些只是单个字节)。结构被打包(使用#pragma pack(1))。

我的问题是:是否可以让结构的数据成员内存地址之一在内存中对齐(例如,地址是否可以被 16 整除)?

我知道可以使用 attribute 对齐整个结构(或者换句话说,它的第一个成员)。我想知道是否可以对齐特定成员而不仅仅是第一个。

基本上我需要打包结构(每个成员都跟在前一个成员之后,没有填充),我需要其中一个成员的地址,而不是第一个,可以被 16 整除。

【问题讨论】:

  • 如果类型的大小不是 16 的倍数,这将永远不会适用于数组。
  • 可能,通过对齐整个结构,然后,用计算器,添加正确数量的填充字节......如果你不能在结构中填充,你可以将它包含在另一个结构并在那里添加填充。此外,您可以将成员移动到开头并对齐结构。
  • 对齐的成员可能会引入填充。
  • @Jarod42:“最整洁”的变体是让对齐的成员位于精确的地址,并且整个(未对齐的)结构相应地移动。比如说,您想要对齐由两个字节组成的结构的第二个字节。该结构将从 align+15 地址开始。
  • @Omer:出于好奇,你需要这个做什么?

标签: c++ gcc


【解决方案1】:

似乎没有任何可能将结构与偏移对齐。您必须自己创建偏移量(填充)。

typedef struct __attribute__((packed)) special_align {
    char misc[3];
    int align_me;
};

typedef struct __attribute__((packed, aligned(16))) pad_container {
    char padding[13];   //16-3
    struct special_align data;
};

当然访问结构会变得更麻烦。 如果您不想手动计算需要多少填充,可以使用offsetof() 宏。在示例中,offsetof(struct special_align,align_me) 将返回 3,即从对齐大小中减去。 (当然如果offset大于align,则必须使用对应的pad size multiplier。`

 pad_size = (sizeof(special_align) * align_size - offsetof(special_align,align_me)) % align_size;

【讨论】:

  • 这是巨大的帮助。谢谢。到目前为止的解决方案是肮脏的并且使用了运行时计算。这会让我做得更好。
  • 注意焊盘尺寸计算你不需要像 sizeof(special_align) * align_size 这样大的乘数,但你需要一个大于 sizeof(special_align) 的 align_size 乘数(以避免所有负模的混乱) .无论如何,它都会被% align_size 标准化为最少的数量,但是找到“最小乘数大于”比“某个乘数大于”要复杂得多,只要 size*offset_size 不超过 MAX_INT,就不会造成麻烦,只有真正巨大的结构才会出现这种情况。
  • 我向某人展示了这个,他告诉我填充大小可以简单地是(对齐 - (偏移 % 对齐)),在我看来他是对的
  • 但是如何实现自动化呢?如果您尝试将公式放在填充定义中(鸡/蛋情况),您会得到“不完整类型的无效使用”:-(
  • @RustyX:我想这需要在 C 预处理器语言中进行一些巧妙的编程 :) 由于结构在编译时几乎是固定的,因此必须在编译之前确定填充的大小 - 在预处理时间。不过不要问我怎么写。我在 C 预处理器方面很差。不过,我想这是一个很好的主题。用 C 编写(非工作)部分并询问如何将其转换为预处理器指令:)
【解决方案2】:

#pragma pack(1) 很讨厌——一旦为给定结构设置了它,它将应用于该结构的每个成员。 alignas__attribute__((packed, aligned(8)))std::aligned_storagestd::aligned_union#pragma pack() 构造在该结构内都不会影响对齐,原始包装将保持整个结构(中间#pragma pack() 将适用于随后的任何内部结构,但外部结构将使用其原始包装进行包装。

因此,唯一的解决方案是手动打包结构,在必要时添加填充字节。

我正在使用这样的东西,它会触发编译器错误并显示(不正确的)对齐方式:

template<int s> struct OffsetIs;

template<int N>
struct CheckAlignment {
  static constexpr size_t ok = sizeof(OffsetIs<N>);
};

template<>
struct CheckAlignment<0> {
  static constexpr bool ok = true;
};

#pragma pack(1)
struct MyStruct
{
  char a;
  //char pad[3]; // uncomment to make it compile
  long x;
};
#pragma pack()

static_assert(CheckAlignment<offsetof(MyStruct, x) % 4>::ok, "Alignment of x is wrong");

【讨论】:

    猜你喜欢
    • 2015-05-05
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    • 2015-04-12
    • 2012-04-18
    • 2021-01-16
    相关资源
    最近更新 更多