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

标签 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*,编译器肯定不会优化访问,但它不是 volatile。

最佳答案

来自C11 draft

An integer may be converted to any pointer type. Except as previously specified [when the integer evaluates to 0], the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

基本上,C 标准不处理手动创建的地址,只处理从对象中获取的地址。


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

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

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

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


简而言之,您的案例没有完全涵盖在标准中。
但是有一个笔记阅读

The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.

这意味着虽然标准不提供任何保证,但您可以期望编译器的行为合理。
此外,按照标准,应该记录整数指针映射。


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

2 引用附件 J,具体实现行为,具体实现方面的列表:
- 将指针转换为整数或相反的结果。
- 任何对象中字节的数量、顺序和编码

关于c - 是否允许 C 编译器优化对未分配内存的访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36531847/

相关文章:

c - 为什么在将 malloc() 指针分配给 char* 时出现段错误?

c - C 中的字符串数组指针仅传递一个字符

C: 将字节数组声明为 uint8_t 有什么问题吗?

c++ - 如何在 C 中将 u_char* 转换为 char[]

c++ - 从 c/c++ 独立应用程序中的 zip 文件导入 python 包

c - 如何使用 fork() 创建一定数量的子进程

c - 接收字符串消息时出现段错误

c - 什么是常量数组?

c - 反转 PPM 图像的值

c - fscanf 没有正确读取文件 ~ 读取 HEX 格式字节的问题