我写了一个像这样的动态数组:
#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
来检索容量和长度信息。
这个想法适用于小型测试。然而,海湾合作委员会警告要打破严格别名。
我还发现了一些没有-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);
答案 0 :(得分:1)
C标准预见到这种技术的技术是灵活的数组,正如已经提到的那样:
typedef struct {
size_t capacity;
size_t len;
unsigned char data[];
} dynarray_header;
如果您分配(或重新分配)具有足够空间的struct
,您可以像任何data
数组一样访问unsigned char
元素。 char
类型可以为任何其他数据类型添加别名,因此您不会遇到任何问题。
如果您的编译器不支持灵活数组,只需在[1]
放置一个data
。
BTW,以下划线开头的名称在文件范围内保留,您不应该使用这些名称。
答案 1 :(得分:0)
-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
- 限定的。 (我假设您的用例,它们不是,至少在触发seg-faults的上下文中。)
仍然......正如丹尼斯·里奇所说,这似乎与实施无关紧要。&#34;或者,换句话说,一个黑客。祝你好运!
(编辑:正如卡尔上面提醒我的那样,在C99你可以使用灵活的阵列成员。我还没有使用它们,因为C99支持似乎不是我使用的C编译器中的默认值这是IBM的参考资料:http://pic.dhe.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Frzarg%2Fflexible.htm)