我正在尝试检查我的一些代码是否存在严格的别名违规行为,但是它
看起来我在尝试理解严格的别名时错过了一些东西
规则。

想象以下代码:

#include <stdio.h>

int main( void )
{
    unsigned long l;

    l = 0;

    *( ( unsigned short * )&l ) = 1;

    printf( "%lu\n", l );

    return 0;
}

经典和基本示例。使用GCC 4.9(-Wall -fstrict-aliasing -Wstrict-aliasing -O3),它实际上报告了错误:
 dereferencing type-punned pointer will break strict-aliasing rules

但是以下代码可以很好地编译:
#include <stdio.h>

int main( void )
{
    unsigned long    l;
    unsigned short * sp;

    l       = 0;
    sp      = ( unsigned short * )&l;
    *( sp ) = 1;

    printf( "%lu\n", l );

    return 0;
}

以我的理解,第二个示例也违反了结构别名规则。
那为什么要编译呢?是GCC中的准确性问题,还是我错过了
有严格别名的东西?

我还找到了以下主题: Why are no strict-aliasing warnings generated for this code?

使用-Wstrict-aliasing=2-Wstrict-aliasing=3编译没有区别。
但是-Wstrict-aliasing=1确实在第二个示例中报告了错误。

GCC文档说,级别1的准确性最低,可以产生很多
误报,而第3级是最准确的...

那么这是怎么回事?我个人理解的问题或GCC的问题?

奖励问题

我的项目通常比GCC更喜欢Clang / LLVM,但似乎Clang
不会发出有关严格别名的任何警告。
有谁知道为什么?
是因为它无法检测到违规,还是因为它没有遵循
生成代码时的规则?

最佳答案

您的理解是正确的。别名分析通常很复杂,在这种情况下,显然仅在强制转换和取消引用之间使用临时指针就足以将其丢弃。令人惊讶的是,GCC 4.8.2在此代码上做得更好,在-Wstrict-aliasing=2以及1级上都发出警告,因此这是一个回归。

至于clang,它目前根本没有警告别名冲突的功能。它确实在优化中充分利用了规则。要实际操作,请直接从C标准(N1570§6.5.2.39)来看这个示例。

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;
}

如果p1和p2指向相同的结构,那么Clang(和GCC)将在否定之前返回p1->m的值,因为它们可能会假定p2没有别名p1,因此先前的否定永远不会影响结果。 Here's the full example并输出带有和不带有-fstrict-aliasing的输出。有关更多示例,请参见here和经常被引用的What Every C Programmer Should Know About Undefined Behavior。严格的别名优化是介绍性文章的最后主题。

至于何时会实现警告the devs are quiet,但提到了in clang's test suite,它在标题(强调我的名字)下列出了-Wstrict-aliasing=X



因此,它似乎有可能在某个时候发生。

10-08 07:36