严格别名规则,误报或误报?

时间:2012-12-04 17:34:44

标签: c gcc-warning strict-aliasing

我在C中遇到严格混叠的问题。我正在使用GCC 4.7.1。

例1:
使用-fstrict-aliasing -Wstrict-aliasing = 3编译此代码时,我收到“警告:取消引用类型惩罚指针将破坏严格别名规则”

#include <stdio.h>
#include <stdint.h>

int main(void)
{
    uint8_t a[4] = {0x01, 0x23, 0x45, 0x67};
    uint32_t b;

    b = *(uint32_t *)a;

    printf("%x\n", b);

    return(0);
}


例2:
此代码不会发出-fstrict-aliasing和-Wstrict-aliasing = 3或-Wstrict-aliasing = 2或-Wstrict-aliasing = 1

的警告
#include <stdio.h>
#include <stdint.h>

int main(void)
{
    uint8_t a[4] = {0x01, 0x23, 0x45, 0x67};
    uint32_t b;
    void *p;

    p = a;
    b = *(uint32_t *)p;

    printf("%x\n", b);

    return(0);
}


两个例子都正常工作。

使用union也是未定义的行为,在我的情况下使用memcpy()太慢了 那么,第一个例子是安全的(误报)还是第二个例子也是不安全的(假阴性)或......?

感谢。

3 个答案:

答案 0 :(得分:4)

如果您想从4 uint32_t制作uint8_t,那么请执行以下操作:制作。不要试图通过指针转换从一个不是一个的东西中拉出一个。你呈现的代码会有所不同,取决于你的平台是小端还是大端,更不用说它只是简单的错误。

他们坏。无论如何,提供的两个样品都是不安全的。这些演员表绕过了数据对齐要求。如果您正在“投射”的任何内容需要比从“投射”投射的任何内容更具限制性的对齐,则会引发总线错误。注意最初的警告。中间指针到空洞只是掩盖了问题(就像大多数问题一样)。

在构建uin32_t时,您希望知道字节“where”。

uint8_t a[4] = {0x01, 0x23, 0x45, 0x67};
uint32_t b = ((uint32_t)a[0] << 24) |
             ((uint32_t)a[1] << 16) |
             ((uint32_t)a[2] << 8) |
             (uint32_t)a[3];

这将总是将a [0]字节放在目标32位无符号的高字节中,在下一个字节中放置[1]等,而不管字节顺序如何。 b 始终0x01234567

答案 1 :(得分:2)

我说第二个例子也不安全 - 只是在那里,编译器不够智能,无法发现pa实际指向相同的(1字节对齐的)位置,并且由于void *无法对齐(根据定义 - 什么是sizeof(void)?),它不会发出警告。

答案 2 :(得分:1)

在这两种情况下,您都是通过另一种类型(uint8_t)访问数组元素(类型uint32_t),这种类型不是原始类型的签名变体,也不是字符类型。

C表示您必须通过自己的类型或签名变体或字符类型访问对象,否则您将违反别名规则。