考虑以下代码。
int main()
{
int* p = (int*)0xABCDEFAB;
int a;
a = *p;
/* do something with a */
return 0;
}
是否允许编译器优化对p
指向的内存位置的访问?因为它没有被分配(因此它的内容是未定义的)并且内存访问不是程序的可观察行为,所以应该允许它,但另一方面,p可能指向内存映射的I / O.
从C标准的角度来看,正式答案是什么?
注意:如果p被定义为volatile int *,编译器肯定不应该优化访问,但它不是易失性的。
答案 0 :(得分:3)
整数可以转换为任何指针类型。除了之前指定的 [当整数计算结果为0] 时, 结果是实现定义的,可能没有正确对齐,可能不指向 引用类型的实体,可能是陷阱表示。
基本上,C标准不处理手工制作的地址,只处理从对象获取的地址。
如果对于您的实现,0xabcdef
被证明是未对齐的,那么引用它将是未定义的行为 1 (并且编译器可以省略加载)。
如果0xabcdef
已对齐,则指针p
可能不会指向地址0xabcdef
或指向int
类型的对象,引用它将是特定于实现的 2 。
在这种情况下,编译器不能直接省略加载,但由于整体行为是特定于实现的,因此最终结果可能是微不足道的并且可以优化。
例如,假设我们有一个编译器,其中以 ab 开头的整数都是
映射到体系结构地址0xffff
,对于目标体系结构,此类地址始终为0(在任何系统中)
编译器可以优化负载并直接将a
清零。
为了防止后一种情况,您需要使用volatile
。
简而言之,您的案件并未完全涵盖在标准范围内 但是有一个笔记读
用于将指向整数或整数的指针转换为指针的映射函数 与执行环境的寻址结构保持一致。
这意味着虽然标准没有给您任何保证,但您可以期望编译器能够合理地行事 此外,根据标准,应记录整数指针映射。
1
引用:
如果为指针分配了无效值,则一元*运算符的行为为
未定义。
2
引自附件J,实施特定行为,实施具体方面的清单:
- 将指针转换为整数的结果,反之亦然
- 任何对象中字节的数量,顺序和编码