为什么即使使用 `char *` 也会收到 "type-punned" 警告?
Why I get a "type-punned" warning even when using a `char *`?
gcc (6.3.1 20170109)编译时如下程序
#include <stdio.h>
int main(int argc, const char *argv[]) {
unsigned char x[] = {0x66, 0x19};
printf("%i\n", ((short *)((char *)&x[0]))[0]);
return 0;
}
生成警告:
pun.c: In function ‘main’:
pun.c:5:5: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
使用 char
指针时不应允许类型别名?
以下是 C11(或至少是自由草案 N1570)关于别名的说法:
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the
object,
- a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
- a character type.
字符类型例外意味着你可以通过char*
或unsigned char*
访问任何类型,但并不意味着你可以通过任何类型访问char*
。 short*
不符合此处为 char*
列出的其他条件,因此此使用是未定义的行为。
此外,如果无条件允许,您可以打破对齐要求:
short x[] = {1, 2};
char* alias = x;
printf("%i\n", *(short*)&alias[1]);
gcc (6.3.1 20170109)编译时如下程序
#include <stdio.h>
int main(int argc, const char *argv[]) {
unsigned char x[] = {0x66, 0x19};
printf("%i\n", ((short *)((char *)&x[0]))[0]);
return 0;
}
生成警告:
pun.c: In function ‘main’: pun.c:5:5: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
使用 char
指针时不应允许类型别名?
以下是 C11(或至少是自由草案 N1570)关于别名的说法:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the object,
- a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
- a character type.
字符类型例外意味着你可以通过char*
或unsigned char*
访问任何类型,但并不意味着你可以通过任何类型访问char*
。 short*
不符合此处为 char*
列出的其他条件,因此此使用是未定义的行为。
此外,如果无条件允许,您可以打破对齐要求:
short x[] = {1, 2};
char* alias = x;
printf("%i\n", *(short*)&alias[1]);