#if 0

变态的C表达式

前阵子与X-man逛书店,一边斜眼看着MM,一边盯着可以找到什么好书。突然,X-man以迅雷不及掩耳盗铃之势出招了:“俺们上学时,有C语言题, 没有学生可以答对,我说你听听?!”。C语言,也算俺看家本领了,面对挑战不能畏惧,只有奋勇直前,“什么玩意儿,这么强?!”。只见X-man不慌不忙,慢慢悠悠地说道:“i初值等于1,加加i加上加加i等于i,最后i等于多少?”,嗯,俺暗付改绕口令了不成?我想了想,道“2+3,等于5呗”,遂见X-man脸上露出小人得意的笑容,“正确答案是6!”,Faint,中招了。
    
    而后没也没太意这个问题,因为谁要是在产品代码写这种表达式,准得挨50屁板儿,然后逐出本派师门。这天晚上在家里、又突然想起这件事,心想权当智力测验了。

下面,是我层层剥茧之后,总结出来的“代码介绍语言”,估计已经可以解释为什么上面的代码等于6了。诚然,文字说明更直观。不过,俺懒呀,大热的天实在不想敲太多文字了。
    
    越是熟悉的角落,越是隐藏着不易发现的秘密。

OK,最后,还是写一些提示吧:

1、局部变量i,是保存在栈上的,没有拷贝!
        2、不要试图编译成汇编代码分析,它们对你理解代码没有什么帮助,这招儿我试过了,后来想想也是不应该有用~
        3、后缀++,和前缀++的求值时间是理解以下程序的另一个关键点。
        4、程序中的注释,也是一些提示。嗯?你觉得它们更像谜语?猜吧。
        5、开动你的脑筋,只有自己想出来的答案,记忆才是最深刻的。
        
#endif

#include <stdio.h>

int
main()
{
    int i;

i = (i=2)+(i=10); /* 10 + 10 */
    printf("%d/n", i);//20

i = 1;
    i = (++i)+(i=10); /* 10 + 10 */
    printf("%d/n", i);//20

i = 1;
    i = (i++)+(i=10); /* 10 + 10 + 1 */
    printf("%d/n", i);//21

i = 1;
    i += ++i; /* 2 += 2 */
    printf("%d/n", i);//4

i = 1;
    i += i++; /* 1 += 1 + 1 */
    printf("%d/n", i);//3

i = 1;
    i = (++i)+(++i); /* 3 + 3 */
    printf("%d /n", i);//6

i = 1;
    i = (++i)+(i++); /* 2 + 2 + 1 */
    printf("%d/n", i);//5

i = 1;
    i = (i++)+(++i); /* 2 + 2 + 1 */
    printf("%d/n", i);//5

i = 1;
    i = (i++)+(i++); /* 1 + 1 + 1 + 1 */
    printf("%d/n", i);//4

i = 1;
    i = (++i)+(i++, i); /* 3 + 3 (汗,这个没看懂)*/
    printf("%d/n", i);//6

}

 
 
 
下面关于自增运算符处理的细节问题,问题如下:

int i = 0;
i = (i++) + (++i);
i = ?
那天小帆同学在群里问起,我图方便,顺手写了个脚本如下:

<html>
<script>
var i = 0;
i = (i++)+(++i);
alert(i);
</script>
</html>

执行该脚本计算得i=2;不想小帆却告诉我i=3!?并给出VC的执行过程:
9: int i=0;
0040B488 mov dword ptr [ebp-4],0
10: i=(i++)+(++i);
0040B48F mov eax,dword ptr [ebp-4] (++i开始)
0040B492 add eax,1 (++i)
0040B495 mov dword ptr [ebp-4],eax (++i结束)
0040B498 mov ecx,dword ptr [ebp-4]
0040B49B add ecx,dword ptr [ebp-4] (i+i,i已执行++i操作,这里是1+1)
0040B49E mov dword ptr [ebp-4],ecx (i=2的赋值操作)
0040B4A1 mov edx,dword ptr [ebp-4] (i++开始)
0040B4A4 add edx,1 (i++)
0040B4A7 mov dword ptr [ebp-4],edx (i++结束)
如果您能看懂以上代码就知道为什么i=3而不等于2了,i的值在最后进行处理,改变了最后的结果。
如果改成如下过程:
int i = 0;
j = (i++) + (++i);
j = ?
汇编码如下:
17: j=(i++)+(++i);
0040B7D9 mov ecx,dword ptr [ebp-4]
0040B7DC add ecx,1
0040B7DF mov dword ptr [ebp-4],ecx
0040B7E2 mov edx,dword ptr [ebp-4]
0040B7E5 add edx,dword ptr [ebp-4]
0040B7E8 mov dword ptr [ebp-8],edx (j=2赋值,注意,结果被放在了高8位)
0040B7EB mov eax,dword ptr [ebp-4] (i++仍然放在最后执行)
0040B7EE add eax,1
0040B7F1 mov dword ptr [ebp-4],eax
很显然,j=2!
通过对比我们应该知道:在表达式的执行过程中,i++操作是放在最后执行的,甚至在"="赋值操作之后。
真相大白,hoho,搞清楚了个问题,值得高兴。
如果再不信,去试试:
i = (i++) + (i++),i是不是等于2? (0+0,接着i两次自加)
j = (i++) + (i++),j是不是等于0? (i没自加前把值赋给了j)
就知道了:)
至于在javascript里执行结果为什么是3?仿佛我对js没什么兴趣,有兴趣的同学去研究吧。
-------------------------------------------------------------------------
Linux版本:
源代码:

#include <stdio.h>

int main()
{
  int i = 1, j = 1, k;

i = (i++) + (++i);
  printf("i=%d /n", i);

k = (j++) + (++j);
  printf("j=%d, k=%d/n", j, k);
}

执行结果:

i=5
j=3, k=4

关键的汇编码片段:

 movl $0x1,0xfffffff0(%ebp)
 movl $0x1,0xfffffff4(%ebp)
 addl $0x1,0xfffffff0(%ebp)
 mov 0xfffffff0(%ebp),%eax
 add %eax,0xfffffff0(%ebp)
 addl $0x1,0xfffffff0(%ebp)
 mov 0xfffffff0(%ebp),%eax
 mov %eax,0x4(%esp)
 movl $0x8048500,(%esp)
 call 80482f8 <printf@plt>
 addl $0x1,0xfffffff4(%ebp)
 mov 0xfffffff4(%ebp),%eax
 add 0xfffffff4(%ebp),%eax
 mov %eax,0xfffffff8(%ebp)
 addl $0x1,0xfffffff4(%ebp)
 mov 0xfffffff8(%ebp),%eax
 mov %eax,0x8(%esp)
 mov 0xfffffff4(%ebp),%eax
 mov %eax,0x4(%esp)
 movl $0x8048507,(%esp)
 call 80482f8 <printf@plt>

明白了以后这就不难解释为什么i=1,执行(++i)+(++i)之后为什么i=6了。

[转贴]变态的C自增相关推荐

  1. 灭霸消灭一般人口是随即的吗_是时候消灭皇家战斗风格了

    灭霸消灭一般人口是随即的吗 Fortnite was my first battle royale, as I'm sure it was for many. I thought at the tim ...

  2. 你的头发一根都不许掉!这款变态洗发皂,7天发量暴增!男同事亲测,20天浓密乌黑!!...

    男神女神的模样有千万种 但有一点一定是标配 那就是拥有一头浓密的乌黑秀发 它是女生颜值翻倍的利器 也是男生形象加分的杀手锏 可随着生活工作精神压力增大 很多人年纪轻轻就开始脱发.生白发 那形象可不比咱 ...

  3. “变态级”系统管理员笔试题,你能拿下吗?

    最近帮助几个企业招聘内网管理员,由于都是外资企业,人家的所有内部应用系统都是Windows环境的,而且是正版.几个HR经理写了一他们的招聘启示给我发了过来,内容大致如下: 1.大学专科或以上计算机或计 ...

  4. SQL Server温故系列(1):SQL 数据操作 CRUD 之增删改合

    1.插入语句 INSERT INTO 1.1.用 INSERT 插入单行数据 1.2.用 INSERT 插入多行数据 1.3.用 INSERT 插入子查询结果行 1.4.INSERT 小结及特殊字段插 ...

  5. 批量模糊查询_Django之ORM表高级操作、增删改查、F/Q查询等

    目录 一.如何开启自己的测试脚本? 二.对表数据的添加.更新.删除1.create()变态操作之批量插入数据2.update()3.delete()4.如何查看QuerySet对象执行的sql语句?5 ...

  6. “变态级”系统管理员笔试题 我的答卷

    试题出自于: 张琦 的51CTO博客 "变态级"系统管理员笔试题,你能拿下吗? [url]http://zhangqi.blog.51cto.com/190185/52893[/u ...

  7. 《变态面试官》系列—Java基础你都不会吧!

    我爱学习,学习使我妈快乐,我妈快乐全家快乐 好看请点赞,不喜请轻喷 锲子 一入编程深似海,编程世界Very深. 这里是九神说编程,今天给大家说的是一个顶级大佬闲的无聊,在编程世界已经999级,闲来无事 ...

  8. etcd 笔记(03)— etcd 客户端使用(键值的增、删、改、查)、watch监测键、lease使用(创建租约、撤销租约、刷新租期、查询租期)

    1. etcd 客户端 etcdctl 是一个命令行客户端,便于我们进行服务测试或手动修改数据库内容,etcdctl 在两个不同的 etcd 版本(v2 和 v3)下的功能和使用方式也完全不同. 一般 ...

  9. java自增运算符与自减运算符

    ++:自增运算法 -- :自减运算法 一般为了方便记忆 把放在 前面的++a 成为前++ 放到后面的a++成为后++ ++a 先+1 在运算 a++ 先运算在++ 例如: x = 2 * ++m 先运 ...

最新文章

  1. 【转载】详解 Spring 3.0 基于 Annotation 的依赖注入实现
  2. 005-对象——对象的 final const
  3. Oracle表空间规划处理
  4. Java中的状态设计模式–示例教程
  5. 新浪的动态策略灰度发布系统:ABTestingGateway
  6. 云计算机是什么样子,云电脑的配置怎么样?高配与标配的区别是什么?
  7. Linux调优/优化
  8. qj71c24n通讯实例_三菱Q系列串行通信模块QJ71C24N概述与特点
  9. 算法分析与设计:棋盘覆盖问题(分治法)
  10. std::vector 初始化的问题 reserve resize
  11. 电动汽车电池换电站选址与定容(Matlab代码实现)
  12. 【MATLAB】基础01
  13. 解决sourcetree特别卡的问题
  14. 【Java笔记】——将晦涩难懂的IO流形象化
  15. 外贸企业电子邮箱哪个好?外贸邮箱怎么选择?
  16. 二、常见的EDID问题
  17. 10Gb每秒!SM4的单核“心”!海泰携手海量数据安全“闪”护
  18. React+Egg.js实现全栈个人博客
  19. eCharts实现多图表切换
  20. 从单张图重建三维人体模型综述(三)

热门文章

  1. 《BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之6---移动增值业务概述
  2. 圆满收官!2022 秋招总结与建议
  3. 圆满收官,百花齐放!2022企业级低代码应用大赛获奖结果公布
  4. 秋招复盘 — 不忘初心,砥砺前行
  5. 日历函数单元 (转)
  6. 02 ,概率论 :初级概念,极差,频率,直方图,曲线图
  7. gcc/g++ 编译C/C++代码
  8. python读取csv数据画直方图_python 中直方图绘制
  9. ArcGIS教程01:面重叠检查
  10. arduino开关控制RGB三色小灯程序,按一下亮一个颜色,松开熄灭,三种不同颜色,程序代码,以及连线图。