当前位置: 华文星空 > 知识

i=1,为什么 (++i)+(++i)=6?

2020-09-18知识

出这种UB(Undefined Behaviour)题目很无聊,这个我已经多次说过了。在实际工作当中写这种代码的首先就应该拉出去毙了。

无论是4,还是5,还是6,都是错的。因为这是个UB,没有标准答案。

但是为什么我还是来答这种问题,因为我认识到这种问题被频频拿出来考新手,是因为新手很容易在这里翻车。而研究新手为什么很容易在这里翻车,我觉得是有意义的。

所以本回答旨在探讨新手为什么容易在这里翻车,思维的陷阱到底在哪里。(本回答并不是为了解释这个UB的成因本身,本回答其实也不太适合对计算机组成原理不熟悉的同学,当然你要看我也没办法,但是包教不包会,据此面试后果自负)

++i,如果单独写成一个语句,等同于i=i+1。我想这个应该没有人有问题。

但是其实这里应该是有问题的,特别是新手。对于新手来说,如果没有意识到这里的问题,那么就很可能在上面那个题目当中翻车。

什么问题呢?

i=i+1,这个式子,在数学上是不成立的。或者说是无解的。(为防止被数学大佬喷,限定一下在初等数学范围内。。。)

也就是说,程序当中的表达式,并不是完全等同于数学公式。因此,不能以代数方程的理念去理解它。

程序当中的i=i+1,其实应该理解为:从一个名叫i的地方(内存空间)取出一个数,将其加1,然后放入名叫i的地方。

也就是,程序当中的表达式,其实只是一系列语句(statement)的简写。i=i+1写成完整语句,其实是:

  1. load i -> 某CPU寄存器
  2. 将该寄存器内容+1
  3. save该寄存器内容 -> i

所以,(++i)+(++i)的意思其实是:

  1. load i -> 某CPU寄存器 (第一个括号
  2. 将该寄存器内容+1
  3. save该寄存器内容 -> i
  4. load i -> 某CPU寄存器 (第二个括号
  5. 将该寄存器内容+1
  6. save该寄存器内容 -> i
  7. load i -> 某CPU寄存器 (两个括号之间
  8. load i -> 另一个CPU寄存器
  9. 将两个寄存器内容相加

(但是注意虽然上面编了序号,但是1-3和4-6之间其实是并列关系,并非要按照序号顺序执行。7和8也是并列关系,可以按任何顺序执行。而这种执行的顺就是导致这个问题是个UB问题的原因)

这样就应该没有人还是认为结果一定是4了吧。

新手掉坑里的原因就在于,把程序当中的表达式当作数学式子,把其中的字母当作未知数。

而理解表达式并不等同于数学式子,变量也不等同于未知数,在我看来是此类问题唯一的价值。

2001/02/19 补充: