我们说int
和float
都是4字节对齐的。根据ISO C99 6.3.2.3第7页:
指向对象或不完整类型的指针可以转换为 指向不同对象或不完整类型的指针。如果结果 指针未正确对齐指向类型的行为 未定义。
根据这一点,以下代码不应该调用UB:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i = 7;
float *f = (float *) &i;
exit(0);
}
我注意到GCC并不总是擅长捕获严格的别名规则违规尝试,但是这里可以正确警告解除引用* f 将中断将违反严格别名规则什么是非法的6.5 p 。 7:
对象的存储值只能通过左值表达式访问 具有以下类型之一:
- 与对象的有效类型兼容的类型
- 与有效类型兼容的类型的限定版本 对象,
- 一种类型,是与之对应的有符号或无符号类型 有效的对象类型,
- 与a对应的有符号或无符号类型的类型 对象的有效类型的限定版本,
- 包含上述之一的聚合或联合类型 其成员之间的类型(包括,递归地,成员 subaggregate或contains union),或
- 字符类型。
$ gcc -Wall -fstrict-aliasing -Wstrict-aliasing=2 so1.c -Wcast-align
so1.c: In function ‘main’:
so1.c:7:2: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
so1.c:7:9: warning: unused variable ‘f’ [-Wunused-variable]
这是否意味着只有当* f被解除引用并且它在当前形状下100%正确时,此代码才可以调用UB?
修改
还有一件事 - 如果float与int的大小不同,那么这个演员也是合法的,但两种类型的对齐方式仍然相同吗?我想是的,因为这是C标准所说的,但我不明白为什么对齐在这里是最重要的而不是尺寸。为什么在转换指针时以及仅在解除引用时对齐很重要?