【发布时间】: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指向的对象”? (重点是,相同的对象不是由不同的指针指向的,而是不同的。)