首页 文章

严格别名和指向联合字段的指针

提问于
浏览
4

我有一个关于严格别名规则,工会和标准的问题 . 假设我们有以下代码:

#include <stdio.h>

union
{
    int f1;
    short f2;
} u = {0x1};

int     * a = &u.f1;
short   * b = &u.f2;

int main()
{
    u.f1 = 1;
    *a += 1;
    u.f2 = 2;
    *b *= 2;

    printf( "%d %hd\n", *a, *b);

    return 0;
}

现在让我们看看它是如何工作的:

$ gcc-5.1.0-x86_64 t.c -O3 -Wall && ./a.out 
2 4
$ gcc-5.1.0-x86_64 t.c -O3 -Wall -fno-strict-aliasing && ./a.out 
4 4

我们可以看到严格别名会破坏依赖关系 . 此外,它似乎是一个正确的代码而不破坏严格别名规则 .

  • 结果是否在工会字段的情况下,铺设在该地址的对象与所有类型的工会成员兼容?

  • 如果1为真,那么编译器应该如何处理指向union成员的指针?这是标准中的一个问题吗? allows 这样的编译器行为?如果没有 - 为什么?

  • 一般来说,编译器使用正确代码的不同行为在任何情况下都是不允许的 . 所以它似乎也是一个编译器错误(特别是如果将地址转换为union字段将在函数内部,SA不会破坏依赖性) .

2 回答

  • 3

    C标准表明明确允许通过联合进行别名化 .

    但请检查以下代码:

    void func(int *a, short *b)
    {
         *a = 1; 
         printf("%f\n", *b);
    }
    

    严格别名规则的目的是假定 ab 不是别名 . 但是你可以调用 func(&u.f1, &u.f2); .

    为了解决这个难题,一个常识性的解决方案是说,工会必须避免严格别名规则的“旁路许可”仅适用于通过名称访问工会成员的时间 .

    标准没有明确说明这一点 . 可以认为“如果成员使用......”(6.5.2.3)实际上是指定仅在通过名称访问成员时发生“旁路”,但它并非100%清楚 .

    然而,很难提出任何替代和自我一致的解释 . 一种可能的替代解释是,写入 func(&u.f1, &u.f2) 会导致UB,因为重叠的对象被传递给一个函数'knows'它没有收到重叠的对象 - 有点像 restrict 违规 .

    如果我们将第一个解释应用于您的示例,我们会说 printf 中的 *a 会导致UB,因为存储在该位置的当前对象是 short ,并且6.5.2.3没有启动,因为我们没有使用union成员按名字 .

    我猜根据你发布的结果,gcc正在使用相同的解释 .

    这已在此处讨论过,但我现在找不到该主题 .

  • 2

    C99技术勘误3通过在6.5.2.3节中说明,基于联合方法澄清了类型 - 打孔:

    如果用于访问union对象内容的成员与上次用于在对象中存储值的成员不同,则该值的对象表示的相应部分将重新解释为新类型中的对象表示形式如6.2.6所述(有时称为“打字”的过程) .

    参见1042到1044的here

相关问题