6.5.2.3 结构和联合成员中 C 中严格别名规则的例外

2023-12-01

引用自C99标准:

6.5.2.3

5 为了简化联合的使用,做出了一项特殊保证:如果联合包含多个共享公共初始序列的结构(见下文),并且如果联合对象当前包含这些结构之一,允许在联合的完整类型声明可见的任何地方检查它们中任何一个的公共初始部分。如果对应的成员对于一个或多个初始成员的序列具有兼容的类型(并且对于位字段,具有相同的宽度),则两个结构共享公共的初始序列。

对于这种情况有一个例子:

// The following code is not a valid fragment because
// the union type is not visible within the function f.

struct t1 { int m; };
struct t2 { int m; };

int f(struct t1 *p1, struct t2 *p2)
{
    if (p1->m < 0)
        p2->m = -p2->m;
    return p1->m;
}

int g()
{
    union
    {
        struct t1 s1;
        struct t2 s2;
    } u;

    /* ... */
    return f(&u.s1, &u.s2);
}

我添加了一些更改:

#include <stdio.h>

struct t1 { int m; };
struct t2 { int m; };

union u
{
    struct t1 s1;
    struct t2 s2;
};

int foo(struct t1 *p1, struct t2 *p2)
{
    if (p1->m)
        p2->m = 2;
    return p1->m;
}

int main(void)
{
    union u u;
    u.s1.m = 1;
    printf("%d\n", foo(&u.s1, &u.s2));
}

如您所见,我已将联合声明移到外部,以便它在 foo() 中可见。根据标准的评论,这应该使我的代码正确,但看起来严格的别名仍然会破坏 clang 3.4 和 gcc 4.8.2 的代码。

带-O0的输出:

2

使用-O2输出:

1

对于两个编译器。

所以我的问题是:

C 真的依赖联合声明来决定某些结构是否是严格别名规则的例外吗?或者 gcc/clang 都有 bug?

对我来说这似乎真的很糟糕,因为即使函数和联合都在同一个标​​头中声明,这也不能保证联合在具有函数体的翻译单元中可见。


最重要的一点是您的更改(将联合向上移动)并没有更改函数的定义foo根本不。它仍然是一个接收无关指针的函数。在您的示例中,传递的指针是相关的,而在其他地方这可能有所不同。编译器的目标是服务于最一般的情况。更改后函数体有所不同,目前尚不清楚原因。

您要问的问题是关于在您的特定编译器中对某些命令行键实施如何仔细的优化。它与内存布局无关。在正确的编译器中,结果应该是相同的。当两个不同的指针实际上指向内存中的同一位置时,编译器应该处理这种情况。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

6.5.2.3 结构和联合成员中 C 中严格别名规则的例外 的相关文章

随机推荐