【问题标题】:Conforming variant of the old "struct hack" (?)旧的“struct hack”(?)
【发布时间】:2013-08-19 09:45:15
【问题描述】:

我相信我已经找到了一种方法来实现类似便携式 C89 中著名的“struct hack”之类的东西。我很好奇这是否真的严格符合 C89。

主要思想是:我分配足够大的内存来保存初始结构和数组的元素。确切的大小是(K + N) * sizeof(array_base_type),其中K 被选中,所以K * sizeof(array_base_type) >= sizeof(the_struct)N 是数组元素的数量。

首先,我取消引用malloc() 返回的指针以存储the_struct,然后我使用指针算法获得指向结构体后面数组开头的指针。

一行代码价值超过一千字,所以这里是一个最小的实现:

typedef struct Header {
    size_t length;
    /* other members follow */
} Header;

typedef struct Value {
    int type;
    union {
        int intval;
        double fltval;
    } v;
} Value;

/* round up to nearest multiple of sizeof(Value) so that a Header struct fits in */
size_t n_hdr = (sizeof(Header) + sizeof(Value) - 1) / sizeof(Value);

size_t n_arr = 42; /* arbitrary array size here */
void *frame = malloc((n_hdr + n_arr) * sizeof(Value));

if (!frame)
    return NULL;

Header *hdr = frame;
Value *stack_bottom = (Value *)frame + n_hdr;

我主要担心的是最后两个赋值(使用frame 作为指向Header 的指针和指向Value 的指针)可能违反严格的别名规则。但是,我不会取消引用 hdr 作为指向 Value 的指针 - 它只是在 frame 上执行的指针运算,以便访问值数组的第一个元素,所以我没有有效地访问 使用不同类型的指针的相同对象。

那么,这种方法是否比经典的 struct hack(已被官方认定为 UB)更好,还是它也是 UB?

【问题讨论】:

  • 我不知道这个解决方案的一致性,但它对我来说并不新鲜。 ;)
  • @DanielKamilKozar 它可能不是新的 :) 它不是那么先进或任何东西......我也不在乎,我只需要完成这项工作。我需要像 C89 中的灵活结构成员(来自 C99)之类的东西,但是 struct hack 是不符合标准的。所以我想了一下,我能想到的就是这个。
  • dbp-consulting.com/tutorials/StrictAliasing.html 对严格别名进行了很好的讨论。基本上,编译器必须确保修改“stack_bottom”不会同时修改“frame”(反之亦然)。您应该可以使用“(Value *) ((char *) frame + n_hdr)”来做到这一点。
  • @mkfs 这是一个非常有用的链接,谢谢!至于代码,你的意思是(Value *)((char *)frame + n_hdr * sizeof(Value))吗?
  • @mkfs 再者,究竟是“修改stack_bottom”还是“修改stack_bottom指向的对象”? (重点是,相同的对象不是由不同的指针指向的,而是不同的。)

标签: c c89


【解决方案1】:

“显而易见的”(嗯...不是很明显,但无论如何 我的 会想到 :-) )导致这种情况发生的方法是使用矢量化编译器,它以某种方式决定可以将 64 个Headers 加载到来自hdr 的 42 舍入到 64+ 区域的向量寄存器中,该区域来自 malloc,它总是分配足够的空间来进行向量化。将向量寄存器存储回内存可能会覆盖Values 之一。

我认为这个向量化编译器可以指向标准(好吧,如果编译器有手指......)并声明符合性。

不过,在实践中,我希望这段代码能够工作。如果您遇到矢量化编译器,请添加更多空间(使用可以插入最小值的机器相关宏进行四舍五入)并继续充电。 :-)

【讨论】:

  • 这是一个很好的例子 (+1)。还有一件事,这不会导致@mkfs 的建议(通过字符类型别名)也中断吗?此外,是否可以通过使用指向 1(一)Header(即Header (*)[1])或类似的数组的指针对hdr 进行别名化来防止这种矢量化编译器将我的大脑中的地狱矢量化?跨度>
  • 我不确定,我从未真正使用过向量化 C 编译器。我相信它们存在于某些 Cray 和 Convex 系统中,但不知道它们如何选择何时执行此类操作。
  • 好的,谢谢。在接受您的回答之前,我正在等待 mkfs 的回复。解释表示赞赏。我想我会使用我的原始解决方案或char * 别名解决方案,我将非常努力地使用各种编译器在多个优化级别测试我的代码,尝试-fstrict-aliasing-ftree-vectorize 的组合标志。此外,将在 README 中添加一个大的红色启动图像并在 cmets 中添加对其的引用,以便我的库的用户知道 my 代码已损坏,而不是他们的。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-07
  • 1970-01-01
  • 2020-10-16
  • 2020-08-23
  • 1970-01-01
相关资源
最近更新 更多