【问题标题】:void* type cast breaks strict -aliasing?void* 类型转换会破坏严格的混叠?
【发布时间】:2013-06-29 08:06:39
【问题描述】:

我写了一个这样的动态数组:

#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);

【问题讨论】:

  • 零空间开销?您完全处于 Dennis Ritchie(K&R 中的“R”)所说的“与实施毫无根据的亲密关系”的领域。
  • 这不就是灵活数组成员的用途吗?
  • @CarlNorum:好点。这是 C89 还是 C99?
  • @CarlNorum,我想要一个“动态”数组,比如 C++ 中的 std::vector。
  • @JoeZ,例如一个 int 数组:int* arr = dynarray_new()。之后我们可以调整 arr 的大小并使用arr[i] 来访问它。

标签: c malloc dynamic-arrays strict-aliasing


【解决方案1】:

如前所述,C 标准为此类事物预见的技术是灵活数组:

typedef struct {
    size_t capacity;
    size_t len;
    unsigned char data[];
} dynarray_header;

如果您分配(或重新分配)这样的struct 有足够的空间,您可以像访问任何unsigned char 数组一样访问data 元素。 char types 可以为任何其他数据类型加上别名,所以你不会有问题。

如果您的编译器不支持灵活数组,只需在其中添加 [1] 即可获得 data

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

【讨论】:

    【解决方案2】:

    -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 *)&amp;(header-&gt;array_head)

    现在,即使使用严格的别名,编译器也更有可能考虑将指向 __dynarray_header 的指针作为指向该联合中任何内容的指针的别名,除非指针也是 restrict 限定的。 (我假设对于您的用例,它们不是,至少在触发段错误的上下文中。)

    仍然……正如 Dennis Ritchie 所说,这似乎是“与实施毫无根据的亲密关系”。或者,换句话说,黑客。祝你好运!

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

    【讨论】:

    • 但我们还是要使用(__dynarray_header*)array - 1 来检索标题?
    猜你喜欢
    • 2012-02-08
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    • 1970-01-01
    • 2020-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多