美丽的神话 发表于 2024-9-9 17:07:34

从汇编角度看printf传参与i++,++i操纵符

目录
一printf了解准备:

   printf打印序次:

二printf打印i++,++i表明

1引例以及简朴设想

2传参的反汇编:

一printf了解准备:   

   1printf打印序次:

    我们最开始用到的就是printf,在我打仗到函数后,我开始从函数角度去看printf这个尺度输出函数,才意识到“”双引号引起的是个格式字符串参数,而我们提供的变量则称为待打印项。我们在用打印函数的时间实在可以很显着感觉到我们是根据格式字符串自左向右打印到屏幕上。证明如下:
https://i-blog.csdnimg.cn/blog_migrate/e3ac2dac677391d7312f1d0694498a96.png
 逗号在屏幕右边,这样就能证明printf的打印是把双引号引起的内容自左向右打印出来。而且%d和变量是逐一对应的,第一个%d对应第一个变量i,第二个%d对应第二个变量i+1。按我们之前对函数的明白,函数都是我们把参数传过去才开始工作,而且传参是自右向左的(这一点背面汇编可以证得),当然如果我们的参数是表达式,运算序次也是自右向左。
二printf打印i++,++i表明

1引例以及简朴设想

int i = 10;
        printf("%d %d\n",i++,++i); 那上面代码的运行我预想应该是这样的
先算++i,前置++先运算后使用(传10给printf),运算后i为11
再算i++,先使用(传11给printf)i的值,再运算,运算后i为12
打印结果为11  11
现实结果为 11  12
    我原以为是传参数是计算一个表达式把结果传给printf,那表达式++i应该传的10,为什么是12呢?为什么传的第一个参数的值不是第一个表达式的结果而是最终i的值,为什么第二个参数的值又不是12呢?起主要说的是传值给函数不是运算完一个表达式传一个参数,而是将全部参数表达式运算完后,才开始传参。也就是说自右向左第一个前置++i运算后结果确实为11,但printf是调用的是参数表达式运算完后i的值,而i的值在下一个后置++中变成了12,这就是为什么大于结果中为12,而不是10的缘故原由。那为什么打印i++又是11呢,因为i++先使用,后++的特点使得编译器会生存i++前的值,也就是11,printf调用的就是这个被生存的值。
    实在上面的论证照旧有很多疑点的,但是要更清晰地证明要看代码运行的反汇编,如果你不想了解反汇编,遇到这个printf打印i++,++i的组合也可以直接影象成前置++,先运算,再使用i的值,但在函数传参中是等全部表达式运算完后,再传i的值给printf,而后置++则是先生存i++前的值,printf调用的就是这个被生存的值,而不是+1完后的值。
2下面我将介绍传参的反汇编:

https://i-blog.csdnimg.cn/blog_migrate/e4cb497769151c741f1e68a413766487.png

第一行mov    dword ptr ,0Ah   :  把0Ah(这是十六进制的数字十,h不用理会)放入ptr(变量i中)
这步是int i=10;的汇编代码
第二行mov    eax,dword ptr     :  把变量i的值放入寄存器eax中,
第三行add    eax,1                      :  把寄存器eax的值加一
第四行mov   dword ptr ,eax   :  把eax中的值放回变量i中去
上面执行了++i,上面就是把值放到变量i,然后放到寄存器eax中拿去加1,结果返回变量i中。
如图
https://i-blog.csdnimg.cn/blog_migrate/2b4b15da2797190656eb6ea257b1d2aa.png

 https://i-blog.csdnimg.cn/blog_migrate/9513850167355375079a78e58d615721.png
第一行mov     ecx,dword ptr                    把i的值放到寄存器ecx
第二行 mov    dword ptr ,ecx   把ecx的值放到一块内存空间中
第三行 mov    edx,dword ptr                   把i的值又复制存到edx中
第四行 add    edx,1                                   edx中的值加一
第五行mov    dword ptr ,edx                  把edx中的值放回i中去
 上面执行了i++,各人可以看出后置++比前置++多了第一行和第二行两个步骤(所以老师常说后置++比前置++要繁琐就是这个缘故原由)在i+1前先把i的值存到内存空间,这个空间的值是11。
https://i-blog.csdnimg.cn/blog_migrate/0e0ba7aaa2669cb4a8454739ff534714.png
上面说的都是i++,++i的运算过程,还没开始传参,但是我们可以得出,运算序次呢确实是自右向左。
https://i-blog.csdnimg.cn/blog_migrate/f0a47820500c8dfdfe17a5b5ca1a398d.png
第一行和之前相同的是将i中的值放入寄存器eax中。
第二行指的是将eax上的值存到栈顶。(留意:push就是把数据放到栈顶上,可以明白为再存到内存中去)
第三行指的是将那块内存空间上的值放到寄存器ecx上。
第四行也就是把寄存器ecx的值放到内存栈顶。
起首printf都是传值调用,这个时间传参就是将数据复制一份再存到栈上去(我想这里大概会有读者问数据不是已经在内存了吗,为什么要再存一份,因为这是传值调用,是把数据再拷贝一份放到内存中给printf调用),传参是自右向左,从汇编上也可以看出,而且第一个push传的是++i中i的结果,这个i在颠末两次运算后已经变成12,而第二个push传的是一块内存空间的值,而这个值是i++运算前的值,所以为11。
说了这么多实在有读者大概会说为什么不是printf的问题,那是否有办法判定是否是printf的问题呢,有,我们把i++,++i的值传给函数里的printf,看传给Printf函数的值和printf打印的结果是不是一样就行了,一样的话说明和printf的处理无关,如下图。
https://i-blog.csdnimg.cn/blog_migrate/f200e6b7c412eaab731123f6dfcc0de7.png
终于又完成了一篇,这篇涉及到了反汇编,实在都是简朴的英文单词,明白一回生二回熟,如果有问题,请读者们在评论指出,我会实时复兴的!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 从汇编角度看printf传参与i++,++i操纵符