首页 > 解决方案 > 严格别名规则背后的基本原理是什么?

问题描述

我目前想知道严格别名规则背后的基本原理。我知道在 C 中不允许某些别名,其目的是允许优化,但令我惊讶的是,在定义标准时,这是跟踪类型转换的首选解决方案。

因此,显然以下示例违反了严格的别名规则:

uint64_t swap(uint64_t val)
{
    uint64_t copy = val;
    uint32_t *ptr = (uint32_t*)© // strict aliasing violation
    uint32_t tmp = ptr[0];
    ptr[0] = ptr[1];
    ptr[1] = tmp;
    return copy;
}

我可能是错的,但据我所知,编译器应该能够完美而轻松地追踪类型转换并避免对显式转换的类型进行优化(就像它避免对同一类型指针进行此类优化一样)任何东西用受影响的值调用。

那么,我错过了哪些严格别名规则的问题,编译器无法轻松解决以自动检测可能的优化)?

标签: clanguage-lawyerc11strict-aliasing

解决方案


由于在本例中,所有代码对编译器都是可见的,因此编译器可以假设性地确定所请求的内容并生成所需的汇编代码。然而,证明理论上不需要严格的别名规则的一种情况并不能证明不需要它的其他情况。

考虑代码是否包含:

foo(&val, ptr)

的声明在foo哪里void foo(uint64_t *a, uint32_t *b);。然后,foo可能在另一个翻译单元中的 inside ,编译器将无法知道这一点ab指向同一对象的(部分)。

那么有两种选择:一是语言可能允许别名,在这种情况下编译器在翻译时不能根据和不同foo的事实进行优化。例如,每当向 写入内容时,编译器必须生成汇编代码以重新加载,因为它可能已经更改。不允许进行优化,例如在使用它时保留寄存器中的副本。*a*b*b*a*a

第二个选择,二,是禁止别名(特别是,如果程序这样做,则不定义行为)。*a在这种情况下,编译器可以根据和*b不同的事实进行优化。

C 委员会选择了选项二,因为它提供了更好的性能,同时不会过度限制程序员。


推荐阅读