符合旧“struct hack”(?)的变体

我相信我已经找到了一种方法来实现便携式C89中众所周知的“struct hack”。 我很好奇这是否真的严格符合C89。

主要思想是:我分配足够大的内存来保存初始结构和数组元素。 确切的大小是(K + N) * sizeof(array_base_type) ,其中选择K * sizeof(array_base_type) >= sizeof(the_struct)使得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上执行的指针算法才能访问value数组的第一个元素,所以我不能使用不同类型的指针有效地访问同一个对象。

那么,这种方法是否比经典的结构黑客(已被正式认为是UB)更好,还是UB呢?

“显而易见”(嗯……不是很明显,但无论如何都是我的想法:-))导致这种情况破坏的方法是使用矢量化编译器,以某种方式决定它可以加载,比方说,64 Header s从hdr的42-round-up-to-64 +区域进入向量寄存器,该区域来自malloc ,它总是足够分配矢量化。 将向量寄存器存储回存储器可能会覆盖其中一个Value

我认为这个矢量化编译器可以指向标准(好吧,如果编译器有手指……)并声称一致性。

但实际上,我希望这段代码能够正常运行。 如果您遇到矢量化编译器,请添加更多空间(使用可以插入最小值的机器相关宏进行舍入)并充电。 🙂