13

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

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

首先,我取消引用malloc()返回到 store的指针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 数组的第一个元素而执行的指针算术,所以我没有使用不同类型的指针有效地访问同一个对象。

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

4

1 回答 1

5

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

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

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

于 2013-08-19T15:21:55.327 回答