我在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()太慢了
那么,第一个例子是安全的(误报)还是第二个例子也是不安全的(假阴性)或......?
感谢。
答案 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)
我说第二个例子也不安全 - 只是在那里,编译器不够智能,无法发现p
和a
实际指向相同的(1字节对齐的)位置,并且由于void *
无法对齐(根据定义 - 什么是sizeof(void)
?),它不会发出警告。
答案 2 :(得分:1)
在这两种情况下,您都是通过另一种类型(uint8_t
)访问数组元素(类型uint32_t
),这种类型不是原始类型的签名变体,也不是字符类型。
C表示您必须通过自己的类型或签名变体或字符类型访问对象,否则您将违反别名规则。