了解打破严格别名的后果

时间:2014-12-03 00:32:19

标签: c struct unions strict-aliasing

int main()
{
    struct { int x; } foo;

    dostuff(&foo);
    return 0;
}

void dostuff(void *ptr)
{
    struct { int x; } *p = ptr;

    p->x = 5;
}

解除引用p是一种严格别名的违规,因为两个未命名的结构不能互为别名,因为它们不兼容。 现在这些代码会出现什么问题?

修改: 我仍然不确定这个定义的行为是否,因为它们没有相同的标记。

假设他们兼容,以下会有什么不同吗?

union u {
    void *v;
    struct {
        int x;
    } *p;
};

void dostuff(void *ptr)
{
    union u tmp = {.v = ptr};

    tmp.p->x = 5;
}

2 个答案:

答案 0 :(得分:0)

看起来很奇怪|疯狂|令人惊讶|看似矛盾,struct { int x; }struct { int x; }在一个翻译单元中确实声明了不同的类型,如e中所述。 G。 this comment

  

以下会有什么不同吗?

union u {
    void *v;
    struct {
        int x;
    } *p;
};

void dostuff(void *ptr)
{
    union u tmp = {.v = ptr};

    tmp.p->x = 5;
}

您没有指定在此处调用dostuff()的方式,因此您必须考虑与第一个示例中相同的main();如果参数在同一个翻译单元中声明,则类型仍然不兼容 - 结构类型的两个声明再次声明不同的类型,而不管其中是否包含其中一个。 此外,第二版dostuff()void *v重新解释为struct … *p;由于C标准不保证指向void的指针与指向结构类型的指针具有相同的表示形式,因此这种用法并不严格符合。

答案 1 :(得分:0)

您描述的场景可能会出现在不同模块各自使用特定布局声明自己的结构并使用它们交换数据的情况下,并且希望更改头文件中的某些函数来自" extern& #34;范围到"内联"范围。遗憾的是,您的场景属于编译器过去常常支持的有用行为类别,有时候没有实际的替代方案,但标准不再强制要求支持,而且某些编译器在不禁用大范围的情况下无法支持除了无用的破坏和优化之外,还有有用的优化和#34;标准允许。