避免向对齐要求更严格的指针转换
12.13 ID_stricterAlignedCast
访问不符合对齐要求的数据会导致标准未定义的行为。
对象的存储地址与其占用空间的长度相关,如变量的地址往往是其长度的整数倍,这种机制称为“内存对齐”,可提高处理器访问数据的效率,如果对象的地址不符合这种要求,访问对象的效率就会降低,在某些平台上甚至会崩溃,详见“unaligned access”。
每种对象类型都有一个“对齐要求(alignment requirement)”,一般来说占用空间越大的类型,对齐要求越严格,如 char 对象可以存储在任意地址,而 int 对象的地址只应是 sizeof(int) 的整数倍,所以解引用由 char 指针转换成的 int 指针很可能会造成“unaligned access”。
示例:
void foo(unsigned char* p) {
char c = *(char*)p; // Compliant
long n = *(long*)(p + 1); // Non-compliant
....
}
二进制数据转向结构化数据时,这种问题较为常见,例中 p + 1 与 long 型变量的对齐要求不同,不应直接转换。
应改为:
void foo(unsigned char* p) {
char c = *(char*)p; // Compliant
long n;
memcpy(&n, p + 1, sizeof(n)); // Compliant
....
}
用 memcpy 等函数将低对齐要求的数据复制到高对齐要求的对象中,是避免相关问题的通用模式。
例外:
alignas(long) short a[32];
long* p = (long*)a; // Compliant
如果源类型的对齐声明与目标类型相符可不受本规则限制。另外,malloc、calloc 等函数的返回值已具备通用对齐要求,也不受本规则限制。
相关
依据
ISO/IEC 9899:1999 6.3.2.3(7)-undefined
ISO/IEC 9899:2011 6.3.2.3(7)-undefined