C与Java表达式求值差异解析:为何int z=(--y)+(y=10)结果不同?
为什么C和Java中
int z=(--y) + (y=10);的执行结果不一样? 这个问题其实戳中了C和Java在表达式求值规则上的核心差异,咱们拆解开来聊:
首先先把两种语言的代码和结果摆出来:
// C语言代码 int y=3; int z=(--y) + (y=10); // 执行后z的值为20(注:这个结果并非所有C编译器都一致,原因后面说)
// Java语言代码 int y=3; int z=(--y) + (y=10); // 执行后z的值固定为12
先看Java的执行逻辑
Java是个“规矩很多”的语言,它严格规定了所有表达式的求值顺序是从左到右,没有任何模糊空间。咱们一步步走:
- 初始
y=3; - 先计算加号左边的
(--y):这是前缀递减运算符,先把y的值减1变成2,然后这个表达式的结果就是2; - 接着计算加号右边的
(y=10):这是赋值操作,把y改成10,同时这个赋值表达式的结果就是10; - 最后把两个结果相加:
2 + 10 = 12,所以z必然是12。
再看C语言的情况
C就宽松多了,甚至可以说“自由得过火”:
- 首先,C标准没有规定加法运算符两个操作数的求值顺序——编译器可以选择先算左边的
(--y),也可以先算右边的(y=10),完全看编译器的实现和优化策略; - 更关键的是,这个表达式里对变量y进行了两次修改(
--y和y=10),而且这两次修改之间没有“序列点”(简单说就是没有明确的执行分界点),这在C里属于未定义行为。什么是未定义行为?就是标准完全不约束编译器的行为,它可以输出任何结果,甚至做奇怪的优化。
你遇到的z=20的情况,大概率是编译器做了某种优化,比如先执行了y=10,然后把两个操作数都当成10来相加(比如编译器认为(--y)的修改被后续的赋值覆盖了,直接优化成10+10)。但换个编译器或者改个优化级别,结果可能变成12、19甚至其他值,这都是合法的——因为C标准没给这个表达式的结果打保票。
核心差异总结
- Java:追求确定性,所有表达式的执行顺序严格从左到右,每个步骤都有明确规定,结果可预测;
- C:追求性能和编译器自由度,对很多运算符的求值顺序不做约束,同一表达式多次修改同一变量且无序列点时属于未定义行为,结果依赖编译器实现。
内容的提问来源于stack exchange,提问作者l sahithi
相关产品推荐
相关产品推荐

