我相信我已经找到了一种方法来实现便携式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
上执行的指针算法,以便访问值数组的第一个元素,因此我无法有效地访问使用不同类型的指针相同的对象。
那么,这种方法是否比经典的结构黑客(官方认为是UB)更好,还是UB呢?
答案 0 :(得分:5)
“显而易见”(嗯......不是很明显,但无论如何它都是我的心灵:-))导致这种情况破坏的方法是使用以某种方式决定的矢量化编译器可以将64 Header
s加载到来自hdr
的42-round-up-to-64 +区域的向量寄存器中,该区域始终分配给malloc
。量化。将向量寄存器存储回存储器可能会覆盖其中一个Value
。
我认为这个矢量化编译器可以指向标准(好吧,如果编译器有手指......)并声明一致性。
但实际上,我希望这段代码能够正常运行。如果您遇到矢量化编译器,请添加更多空间(使用可插入最小值的机器相关宏进行舍入)并充电。 : - )