【问题标题】:Why does this alignment attribute have to be specified in a typedef?为什么必须在 typedef 中指定此对齐属性?
【发布时间】:2016-12-16 08:21:25
【问题描述】:

我最初是从平板电脑上写下这个问题的,并且在这样做时采取了很多捷径,我认为最终会导致阅读和/或试图回答这个问题的人感到困惑。

我并不是要解决我最初开始遇到的问题。如果您真的想要背景故事,请阅读下一段,否则请跳过它。

造成这种情况的是一些旧代码对{struct, data, struct, data, ...} 形式的数据数组进行操作,其中每个data 具有任意长度。代码通过指针访问每个结构,当我们切换到 gcc 时,由于未对齐的访问,它开始在 Solaris 中崩溃。解决这个问题的一个想法是改变类型的对齐方式,如下所示,但我可能不会这样做。

要回答的问题可以概括为:

  • 文档指出不能用aligned 减少对齐,但我可以用typedef 来做到这一点。是否按预期工作?
  • 如果它按预期工作,为什么它需要 typedef?为什么我不能降低对齐作为结构定义的一部分?
    • 注意:也可以使用typedef struct {...}__attribute__((aligned(1))) Typename; 完成

这是link to some sample code running on wandbox。如果链接失效:

#include <cstdio>
#include <assert.h>

#define ALIGN __attribute__((aligned(1)))

struct       Misaligned_1_t { int x; double y; float z; };
struct ALIGN Misaligned_2_t { int x; double y; float z; };
struct       Misaligned_3_t { int x; double y; float z; } ALIGN;

// The gcc documentation indicates that the "aligned" attribute
// can only be used to increase alignment, so I was surprised
// to discover this actually works.  Why does it work?
typedef Misaligned_1_t ALIGN Aligned_t;

int main( int, char** ) {
  char buffer[256];
  // The following is meant to simulate a more complicated scenario:
  //   {SomeStruct, char[arbitrary length], SomeStruct, char[arbitrary length], ...}
  // ... where accessing, using and changing each SomeStruct will result in
  // misaligned accesses.
  auto *m1 = (Misaligned_1_t*)&buffer[1];
  auto *m2 = (Misaligned_1_t*)&buffer[1];
  auto *m3 = (Misaligned_1_t*)&buffer[1];
  auto *a1 = (Aligned_t*)&buffer[1];

  // The documentation says we can only reduce alignment with the "packed" attribute,
  // but that would change the size/layout of the structs.  This is to demonstrate
  // that each type is the same size (and should have the same layout).
  assert(   sizeof(m1) == sizeof(m2)
         && sizeof(m1) == sizeof(m3)
         && sizeof(m1) == sizeof(a1) );

  m1->y = 3.14159265358979323846264; // misaligned access

  std::printf( "%0.16f\n", m2->y ); // misaligned access
  std::printf( "%0.16f\n", m3->y ); // misaligned access
  std::printf( "%0.16f\n", a1->y ); // works fine

  return 0;
}

【问题讨论】:

  • “为什么必须在 typedef 中指定这个对齐属性?” 反对什么?真正的问题是什么?
  • 为什么struct __attribute__((aligned(1))) Test{...} 不起作用?我对文档的阅读给我的印象是,如果没有packed,我不应该像这样降低对齐方式,但是由于它似乎可以工作,我很好奇为什么没有 typedef 就不能工作
  • aligned(1) 表示将结构对齐到 1 个字节?我不认为这有任何影响。你期待什么效果?
  • 它似乎达到了预期的效果,但我很困惑它是否有效以及为什么没有 typedef 就无法完成
  • 想要的效果是什么?不将结构与堆栈上的默认对齐方式(可能是 8 左右)对齐?

标签: c attributes memory-alignment struct-member-alignment


【解决方案1】:

来自 gcc help files

您可以在 typedef 声明中指定对齐的和 transparent_union 属性,也可以在完整枚举、结构或联合类型定义的右大括号之后指定,以及仅在定义的右大括号之后指定打包属性。

所以你可以使用

struct Test_t {
  int x;
  double y;
  float z;
} __attribute__((aligned(1)));

然后用

定义变量
struct Test_t a,b;
struct Test_t *test;

或者您可以使用上面给出的方式。是一样的。

【讨论】:

  • 不幸的是,即使右大括号在我尝试过的任何编译器中都不起作用。到目前为止,只有 typedef 起作用了
  • 它正在我的编译器(cygwin 5.4.0)上运行。但是,属性不是可移植 C 代码的一部分,因此您应该查看编译器文档以获取有关如何使用它的信息。
  • 哪个编译器和版本?我试过 GCC 4.9.2、5.4、6.somehing 和 clang 3.8
  • 我的尺码为 24,在所有三种情况下,a。没有属性,b.答案中给出的属性,以及 c。应用于 typedef 的属性。 (正确的语法是typedef struct Test_t __attribute__((aligned(1))) Test;
  • 我修改了我的魔杖盒示例来演示这个问题。将属性作为结构的一部分,它会获得未对齐的访问。在 Sparc Solaris 中它会崩溃:melpon.org/wandbox/permlink/MsK5E1zuW4wUScyJ
【解决方案2】:

我找到了答案。我一定是个盲人。来自 GCC 文档:

在结构体或结构体成员上使用时,aligned 属性只能增加对齐;为了减少它,还必须指定打包属性。 当作为 typedef 的一部分使用时,aligned 属性可以增加和减少对齐,并且指定 packed 属性会产生警告。

【讨论】:

    猜你喜欢
    • 2021-12-20
    • 2019-06-23
    • 2019-02-05
    • 1970-01-01
    • 2012-12-14
    • 1970-01-01
    • 1970-01-01
    • 2011-11-28
    • 1970-01-01
    相关资源
    最近更新 更多