我已经使用 C 指针有一段时间了,一切都按预期工作。然而现在我遇到了 ISO 标准,它说“如果生成的指针未针对指向的类型正确对齐,则行为未定义”。
这让我问自己:
这是什么意思?
我们如何安全地将指针转换为其他类型?
我发现这个 C 代码示例据说是不正确的,因为它与更严格对齐的指针类型有关:
int main(){
char c = 'x';
int *ip = (int *)&c;
char *cp = (char *)ip;
return 0;
}
- 更严格对齐的指针类型是什么意思?
C 2018 6.2.8 5 说:
对齐的顺序是从“较弱”到“更强”或“更严格”对齐。更严格的对齐具有更大的对齐值。满足对齐要求的地址也满足任何较弱的有效对齐要求。 如果您没有“对齐”规范,C 2018 6.2.8 1 说: 完整的对象类型具有对齐要求,该要求对该类型的对象可以分配的地址施加限制。对齐是一个实现定义的整数值,表示可以分配给定对象的连续地址之间的字节数......
实际上,这意味着具有对齐要求的对象
A必须从A
倍数的地址开始。
这是什么意思?
考虑一些值为PP
是指针指向的地址。为了回答这个问题,我们将- 的指针。即
P
视为内存空间中的完全解析地址。 (实际的指针可以用对各种基地址或段的引用以及从这些基地址或从段开头的偏移量来表示。)当指针转换为指向不同对象类型的指针时,新的对象类型有一些对齐要求A。如果 P 是 A 的倍数,则 P 与对象类型正确对齐,并且转换会生成一些新的有效指针。 (由于 C 中的其他规则,它不一定是可用于访问新类型的对象的指针。)如果 P 不是 A 的倍数,则 C 标准不定义程序的行为。转换可能不会产生有效的指针,可能会产生调整为正确对齐的指针,程序可能会中止,或者程序可能会以您不期望的方式运行。 我们如何安全地将指针转换为其他类型?
仅当您知道源指针与目标类型正确对齐时,才将指针转换为指向新对象类型的指针。可以提供地址的表示形式,可以测试该表示形式是否是所需对齐的倍数。类型的对齐要求可以通过评估
- C 实现之间类型的对齐要求有所不同。如果指针指向的对象的对齐类型与新类型一样严格或更严格,那么您就知道可以安全地转换它。否则,C 实现可以提供测试对齐的方法。通常,转换为
uintptr_t
_Alignof(type-name)
来获得。
这是什么意思?
你可能会违反棍棒别名规则你可以访问不属于任何对象的内存
char
示例
char array[] = {1,2,3,4};
int *p = (int *)array;
//illegal - undefined behaviour
printf("%d\n", *p);
//correct
int x;
memcpy(&x, array, sizeof(x));
printf("%d\n", x);
// correct - you can use pointer to char to aceess another objects
float f = 1.567f;
unsigned char *pf = (unsigned char *)&f;
for(size_t index = 0; index < sizeof(f); index++)
printf("%hhx\n", pf[index]);
更严格对齐的指针类型是什么意思
我不知道——没听说过。