C语言回头看诡异的i和i

C语言中的i 和 i使用非常的方便,简单明了。但是很多人在学习C语言的过程中,对这两个语句还是存在恐惧,因为这两条语句会引起不必要的麻烦。例如:到底是先用再加,还是先加再用? 同时在一些程序语句中也会出现一些令人意想不到的结果,例如i=1,(( i) ( i))=6的情况,非常的诡异。

因此本文针对这个问题,深入到汇编层面,理解双胞胎i 和 i的故事。相信通过本文,你能够更加深刻的理解C语言中的自加自减等操作。

C语言文件如下所示,逻辑为:分别输出i 和 i的结果。

使用make进行构建,makefile如下所示

本机所用的环境如下所示:

Ubuntu 16.04 (64位,内核版本4.15.0-142-generic)gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12)make:GNU Make 4.1,Built for x86_64-pc-linux-gnu

结果如下:

在ubuntu中我们使用objdump ~d ./selfincre > objdump.txt,将程序进行反汇编,我们将不重要的信息剔除,只保留main函数,如下所示,在部分汇编语句中进行了注释,可以结合‘餐食’。

主要分析一下C代码

i;

汇编如下所示:

i正如字面的意思一样,先加后用!

其加一汇编操作,均在-0x4(%rbp)进行,加一操作为addl $0x1,-0x4(%rbp),因此 i直接造成的结果就是i的改变。

C代码如下

i ;

汇编如下所示:

i 正如字面的意思一样,先用后加!

其加一汇编操作,在寄存器eax的值的基础上进行,加一操作为lea 0x1(%rax),�x;mov �x,-0x4(%rbp)。

我们可以如下理解i , 拆分为两句:

i –> i;i = i 1

i 相当于:先使用i,在对i进行加一操作。

因此i 的结果是i,使用的方法是eax寄存器。只不过在使用完i,会有一个加一的操作而已。

i,先加后用!

i ,先用后加!

出现i , i这样语句的目的可能在于减少语句操作吧。通过上述字面理解,其实是最快的。

使用如下代码进行分析

i = 1;printf(“i = 1,(i ) ( i) = %dn”, (i ) ( i));i = 1;printf(“i = 1,( i) ( i) = %dn”, ( i) ( i));

首先我们先进行一个简单一些的分析,i = 1;(i ) ( i) 的结果是多少呢?

通过第二节的分析,我们知道,其实(i ) ( i)的可以看做(i_1 ( i_2))(i_1是因为此时i_1的值是eax的值,i_1 不等同于i_2,并不随i的值变化), 再由C语言中表达式的计算是由右到左,所以会先计算 i,然后是再相加。那么结果应该是1 2 = 3。

但是,实际结果却是4.为什么呢?

原因就是在进行 i的时候,虽然后续用的是eax的值,但是这句话(第5行)随后进行的操作改变了-0x4(%rbp)的值(第6、7行)。其本意是-0x4(%rbp) 1,但是此时-0x4(%rbp)的值已经被i 修改过了,为2,所以 i的结果就成为了3。最终两式一加,结果为4.

下面我们分析( i) ( i) = 6?

汇编代码如下所示:

经过上一小节的分析,其实这里已经非常简单了,因为两次 i不断的改变-0x4(%rbp)的值,使得-0x4(%rbp)在使用时变成了3,最终两式相加为6.

i = 1;printf(“i = 1,( i) (i ) = %dn”, ( i) (i ));

400598: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)40059f: 83 45 fc 01 addl $0x1,-0x4(%rbp)4005a3: 8b 45 fc mov -0x4(%rbp),�x4005a6: 8d 50 01 lea 0x1(%rax),�x4005a9: 89 55 fc mov �x,-0x4(%rbp)4005ac: 8b 55 fc mov -0x4(%rbp),�x4005af: 01 d0 add �x,�x4005b1: 89 c6 mov �x,%esi4005b3: bf ac 06 40 00 mov $0x4006ac,�i4005b8: b8 00 00 00 00 mov $0x0,�x4005bd: e8 3e fe ff ff callq 400400

他的结果是5,通过上述分析,你算对了吗?

关键提示:

虽然这有点复杂,感觉确定性非常的不高。但是不用担心,在C语言的编译过程中,会警告我们,这样的语句中i没有定义。如果你发现这样的问题后,就需要注意了。

下面文章中对这个问题进行了解释,不再赘述。

i=1,为什么 ( i) ( i)=6? – CWKSC的回答 – 知乎 https://www.zhihu.com/question/347864795/answer/836263029

未经允许不得转载:股市行情网 » C语言回头看诡异的i和i

相关文章

评论 (0)