是否允许C编译器优化对未分配内存的访问?

时间:2016-04-10 15:44:24

标签: c

考虑以下代码。

int main()
{
  int* p = (int*)0xABCDEFAB;
  int a;

  a = *p;

  /* do something with a */

  return 0;
}

是否允许编译器优化对p指向的内存位置的访问?因为它没有被分配(因此它的内容是未定义的)并且内存访问不是程序的可观察行为,所以应该允许它,但另一方面,p可能指向内存映射的I / O.

从C标准的角度来看,正式答案是什么?

注意:如果p被定义为volatile int *,编译器肯定不应该优化访问,但它不是易失性的。

1 个答案:

答案 0 :(得分:3)

来自C11 draft

  

整数可以转换为任何指针类型。除了之前指定的 [当整数计算结果为0] 时,   结果是实现定义的,可能没有正确对齐,可能不指向   引用类型的实体,可能是陷阱表示。

基本上,C标准不处理手工制作的地址,只处理从对象获取的地址。

如果对于您的实现,0xabcdef被证明是未对齐的,那么引用它将是未定义的行为 1 (并且编译器可以省略加载)。

如果0xabcdef已对齐,则指针p可能不会指向地址0xabcdef或指向int类型的对象,引用它将是特定于实现的 2
在这种情况下,编译器不能直接省略加载,但由于整体行为是特定于实现的,因此最终结果可能是微不足道的并且可以优化。

例如,假设我们有一个编译器,其中以 ab 开头的整数都是 映射到体系结构地址0xffff,对于目标体系结构,此类地址始终为0(在任何系统中) 编译器可以优化负载并直接将a清零。

为了防止后一种情况,您需要使用volatile

简而言之,您的案件并未完全涵盖在标准范围内 但是有一个笔记读

  

用于将指向整数或整数的指针转换为指针的映射函数   与执行环境的寻址结构保持一致。

这意味着虽然标准没有给您任何保证,但您可以期望编译器能够合理地行事 此外,根据标准,应记录整数指针映射。

1 引用:
如果为指针分配了无效值,则一元*运算符的行为为 未定义。

2 引自附件J,实施特定行为,实施具体方面的清单:
- 将指针转换为整数的结果,反之亦然 - 任何对象中字节的数量,顺序和编码