You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内联C函数时编译器能否多解引用指针?C标准合规性问询

C编译器内联函数时能否将单次指针解引用优化为两次?

原始代码

int y = 1;
int* p = &y;

inline int f(int x) {
  return x + x;
}

int g(void) {
  return f(*p);
}

问题描述

上述代码中仅存在一次显式指针解引用。请问C编译器是否允许将其编译/优化为如下近似代码:

int g(void) {
  return *p + *p;
}

即内联函数f时,编译器能否执行并使用两次独立的目标内存访问,而非源码中实际编写的单次访问?C标准中是否有具体条款允许或禁止该行为?注:示例中p并非volatile类型,且优化后的代码至少在功能上是正确的。

(请注意,问题并非‘编译器是否会这么做’或‘编译器应该这么做’,而是根据C标准,编译器能否这么做。假设寄存器溢出使得二次解引用更高效等场景。)

参考C99标准,曾考虑过一些关于参数处理的条款,比如‘每个参数被赋予对应实参的值’(6.5.2.2)或‘其(参数的)标识符是左值’(6.9.1)可能会阻止该场景,但该解释似乎与常见的参数优化不符。


回答

根据C99标准,编译器允许进行这样的优化,核心依据如下:

  1. 抽象机的可观察行为一致性原则

C99 5.1.2.3 程序执行中明确规定:在抽象机中程序严格按规则执行,但实际实现可省略任何不必要的计算,只要省略后的结果与抽象机执行结果的可观察行为一致。可观察行为包括volatile对象的修改、输入输出操作,以及对volatile对象的读取。

由于示例中的p并非volatile类型,且在g()执行过程中没有任何会修改y的可观察行为(比如并发修改、信号处理函数修改等),因此两次读取*p的结果在抽象机中与单次读取后复用值的结果完全一致,这种优化符合标准要求。

  1. 函数参数传递的规则解读
    C99 6.5.2.2 函数调用中提到“每个参数被赋予对应实参的值”,这里的“值”指的是实参表达式的计算结果,但标准并未强制要求编译器必须在调用点只计算一次实参表达式。只要多次计算实参不会改变程序的可观察行为,编译器就有权选择多次求值——这也是常见参数优化的依据。

  2. 参数作为左值的条款不限制此优化
    C99 6.9.1 函数定义中提到参数标识符是左值,这仅指函数内部对参数的操作是针对该参数的副本(因为C函数参数默认按值传递),但这并不限制编译器在调用点对实参表达式的求值次数。函数内部的x + x操作针对的是参数副本,编译器完全可以将其展开为两次读取原始实参的内存,只要行为一致。


内容的提问来源于stack exchange,提问作者john smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 01:23:14