关于未定义行为的一些研究

 

运行结果取决于未定义行为的一些不良写法,可总有人拿出来当题考别人。。。

首先printf()函数里面参数的求值顺序,标准C里只规定了四个运算符的求值顺序,||,&&,?:,还有逗号,但不是函数参数表里的逗号。

基于任何关于函数参数求值顺序的假设都是危险的行为。

至于printf的求值顺序在VC6.0和Gcc里面都是从右到左的。

所以第一个printf的输出两个编译器是相同的?NO。。。

还有一个++和--运算符的问题。。。。

在VC6.0中的输出是

3,2

在GCC中的输出是

4,2

分别进行反汇编,观察一下就明了了,VC6.0中的disassembly


  

可以明白地址为ebp-4的内存就是存储变量b的地方,传参的时候,先做了一份拷贝放入eax中,然后又拷贝到ebp-8,然后ebp-8又拷贝到ecx,最后将ecx压入栈中。然后将b的值拷贝到edx,进行++b,操作完之后更新b的值,然后把更新过的值拷贝到eax中,并且入栈。

所有参数入栈之后,将b的值再放入ecx中,进行b++,然后更新b的值,然后调用函数。。。

实际上的结果同

 int b,a;
 a=b=2;
 ++b;
 printf("%d,%d/n",b,a);
 a++;

然后是GCC,GCC中的反汇编器的结果是

 

汇编代码比VC的简单一些

继续,语句改成

printf("%d,%d/n",b++,++b);

结果是多少呢

VC6.0中为

3,3

GCC中为

3,4

VC6.0的反汇编结果

不管b++的位置在左边还是右边,在VC6.0中是全部参数入栈之后调用函数之前更新b的值

在GCC中的反汇编结果

在GCC中,b++作为参数,是在保存了b更新前的值之后,就立刻进行b++。。。当然是在参数入栈之前

printf("%d,%d",b++,b++);的结果呢

利用上面的分析

VC6.0中应该是2,2

GCC中应该是3,2

事实也的确是这样的。。。。

再来一个问题,

int b=2;

int a1=++b+(++b);

a1的值是多少?

a2=++b+(b++)呢?

a3=b+++(++b)呢?

VC6.0中

a1的值为8

a2的值为6

a3的值为6

a2为例,反汇编器结果,实际上a3的结果也是一样的,优先计算++b么??

在GCC中结果是一样的。。。

 

结论

1)在VC6.0中,不管b++的位置在左边还是右边,全部参数入栈之后,调用函数之前,b++才会进行。

2)在GCC: (GNU) 4.2.4中,b++作为参数,是在保存了b更新前的值之后,就进行b++操作,并更新b的值,是在参数入栈之前。

3)上述都是不好的行为,旨在自虐和练习读汇编。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值