我写了这样的动态数组:

#include <stdlib.h>

typedef struct {
    size_t capacity;
    size_t len;
} __dynarray_header;

void* dynarray_new() {
    __dynarray_header* header = malloc(sizeof(__dynarray_header));
    header->capacity = 0;
    header->len = 0;
    return header + 1;
}

可以使用[]操作访问动态数组。调整大小时,我可以使用__dynarray_header*)array - 1检索容量和长度信息。

这个想法适用于小型测试。但是,GCC警告不要破坏严格的混叠。

我还发现一些没有-fno-strict-aliasing编译器选项(带有-O3优化)的大型项目段错误。

我知道什么是严格别名,为什么我的代码会破坏严格别名。

我的问题是:有没有比上面显示的方法更好的方法来实现同时支持[]操作和动态调整大小的动态数组?

额外:

使用此动态数组的演示程序:
int* arr = dynarray_new();
arr = dynarray_resize(sizeof(int) * 2);
arr[0] = 1;
arr[1] = 2;
arr = dynarray_resize(sizeof(int) * 4);
arr[2] = 3;
arr[3] = 4;
dynarray_free(arr);

最佳答案

-fstrict-aliasing提供的主要优化是,在大多数情况下,对foo *的引用可以随意移到对bar *的引用之外。您看到的段错误很可能是由于引用移到某个地方的free类型操作之外。

尽管这有点脏,但您可以通过在结构中添加预期数组元素类型的并集来使其在C89下工作,例如:

typedef struct {
    size_t capacity;
    size_t len;
    union {
        int i;
        double d;
        my_type mt;
        etc e;
        /* add additional types here. */
    } array_head;
} __dynarray_header;

然后,不返回header + 1,而是返回(void *)&(header->array_head)

现在,即使使用严格的别名,编译器也更有可能考虑指向__dynarray_header的指针,以便可能将指向该联合中任何内容的指针别名,除非这些指针也具有restrict限定的资格。 (我假设对于您的用例,至少在触发段故障的情况下,它们不是。)

仍然……就像丹尼斯·里奇(Dennis Ritchie)所说,这似乎是“对实现的不必要的笨拙”。换句话说,就是骇客。祝好运!

(编辑:正如上面的卡尔提醒我的那样,在C99中,您可以使用灵活的数组成员。我没有使用它们,仅仅是因为C99支持似乎不是我使用的C编译器中的默认值。这是IBM的参考:http://pic.dhe.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Frzarg%2Fflexible.htm)

关于c - void *类型强制转换是否严格-aliasing?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17417410/

10-12 20:48