首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >空*类型转换破坏了严格的-aliasing?

空*类型转换破坏了严格的-aliasing?
EN

Stack Overflow用户
提问于 2013-07-02 12:29:01
回答 2查看 1.4K关注 0票数 3

我写了一个动态数组,如下所示:

代码语言:javascript
复制
#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优化)的较大项目。

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

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

额外的:

使用此动态数组的演示程序:

代码语言:javascript
复制
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);
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-07-02 12:39:13

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

虽然这感觉有点脏,但您可以通过将预期数组元素类型的联合添加到您的结构中,使其在C89下工作,例如:

代码语言:javascript
复制
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;

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

现在,即使有严格的别名,编译器也更有可能考虑指向__dynarray_header的指针,以可能为指向该联合中任何内容的指针提供别名,除非这些指针也是restrict-qualified。(我假设对于您的用例,它们不是,至少在触发seg-faults的上下文中是这样的。)

不过..。正如Dennis Ritchie所说,这似乎是“与实现毫无根据的亲密关系”。或者,换句话说,一次黑客攻击。祝好运!

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

票数 0
EN

Stack Overflow用户

发布于 2013-07-02 13:21:41

正如前面已经提到的,C标准为这种事情预见的技术是灵活的数组:

代码语言:javascript
复制
typedef struct {
    size_t capacity;
    size_t len;
    unsigned char data[];
} dynarray_header;

如果您分配(或重新分配)这样一个具有足够空间的struct,则可以像访问任何unsigned char数组一样访问data元素。char类型可以是任何其他数据类型的别名,因此您不会有任何问题。

如果你的编译器不支持灵活的数组,只需为data添加一个[1]即可。

顺便说一句,以下划线开头的名称在文件范围内是保留的,您不应该使用这些名称。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17417410

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档