兰州天气,你真的懂c语言和- -算符吗?-安博电竞竞猜-安博电竞

188体育 295℃ 0

这个主题关于刚开端学习C言语时或许会觉得很简单啊,那好你告诉我下面几个标题的输出是什么,你要是能说对,并且说出为什么,那你就能够不必往下看了:

int i = 0,j = 0;1、j = (i++)+(i++)+(i++); //而不是j = i++i++i++;2、j = (++i)+(++i)+(++i)彝; //而不是j = ++i++i++i;3濯、j = ++i+++i+++i;4、j = i+++j;

下面咱们一题一题来进行剖析:

首要:咱们来剖析1和2两个题,这儿需求略微懂点汇编常识,由于C言语是剖析不出来的,所以只能从汇编的视点去剖析;

可是不明白汇编言语也不必怕,由于我也不明白汇编言语,用到我都是百度查询,有的也不是很懂,下面我在VS2010里边编写上面代码:

#include 
#include
int main()
{
int i = 0,j = 0;
//榜首题
j = (i++)+(i++)+(i++);
//下面咱们自己剖析下以为应该是
//j= 0 + 1 + 2;i = 3
printf("i = %d,j = %d
",i,j); //实践输出i = 3 j = 0
//第二题
j = (++i)+(++i)+(++i);
//下面咱们自己剖析下以为应该是
//j = 4 + 5 + 6; i = 6
printf("i = %d,j = %d
",i,j); //实践输出i = 6 j = 18
//第三题
//j = ++i+++i+++i; //编译犯错
//printf("i = %d,j = %d
",i,j);
//第四题
j = i+++j;
printf("i = %d,j = %d
",i,j);
system("pause");
return 0;
}


再看下对应反汇编代码

#include 
#include
int main()
{
003A34A0 push ebp
003A34A1 mov ebp,esp
003A34A3 sub esp,0D8h
003A34A9 push ebx
003A34AA push esi
003A34AB push edi
003A34AC lea edi,[ebp-0D8h]
003A34B2 mov ecx,36h
003A34B7 mov eax,0CCCCCCCCh
003A34BC rep stos dword ptr es:[edi]
int i = 0,j = 0;
003A34BE mov dword ptr [i],0
003A34C5 mov dword ptr [j],0
//榜首题
j = (i++)+(i++)+(i++);
003A34CC mov eax,dword ptr [i]
003A34CF add eax,dword ptr [i]
003A34D2 add eax,dword ptr [i]
003A34D5 mov dword ptr [j],eax
003A34D灶君诞8 mov ecx,dword ptr [i]
003A34DB add ecx,1
003A34DE mov dword ptr [i],ecx
003A34E1 mov edx,dword ptr [i]
003A34E4 add edx,1
003A34E7 mov dword ptr [i],edx
003A34EA mov eax,dword ptr [i]
003A34ED add eax,1
003A34F0 mov dword ptr [i],eax
刘文正//下面咱们自己剖析下以为应该是
//j= 0 + 1 + 2;i = 3
printf("i = %d,j = %d
",i,j); //实践输出i = 3 j = 0
003A34F3 mov esi,esp
003A34F5 mov eax,dword ptr [j]
003A34F8 push 兰州气候,你真的懂c言语和- -算符吗?-安博电竞竞猜-安博电竞eax
003A34F9 mov ecx,dword ptr [i]
003A34FC push ecx
003A34FD push offset string "i = %d,j = %d
" (3A5A00h)
003A3502 call dword ptr [__imp__printf (3A82B0h)]
003A3508 add esp,0Ch
003A350B cmp esi,esp
003A350D call @ILT+295(__RT哀痛的句子C_CheckEsp) (3A112Ch)
//第二题
j = (++i)+(++i)+(++i);
003A3512 mov eax,dword ptr [i]
003A3515 add eax,1
003A3518 mov dword pt兰州气候,你真的懂c言语和- -算符吗?-安博电竞竞猜-安博电竞r [i],eax
003A351B mov ecx,dwo性感蕾丝rd ptr [i]
003A351E add ecx,1
003A3521 mov dword ptr [i],ecx
003A3忍者524 mov edx,dword ptr [i]
003A3527 add edx,1
003A352A mov dword ptr [i],edx
003A352D mov eax,dword ptr [i]
003A3530 add eax,dword ptr [i]
003A3533 add eax,dword ptr [i]
003A3536 mov dword ptr [j],eax
//下面咱们自己剖析下以为应该是
//j = 4 + 5 + 6; i = 6
printf("i = %d,j = %d
",i,j); //实践输出i = 6 j = 18
003A3539 mov esi,esp
003A353B mov eax,dword ptr [j]
003A353E push eax
003A353F mov ecx,dword ptr [i]
003A3542 push ecx
003A3543 push offset string "i = %d,j = %d
" (3A5A00h)
003A3548 call dword ptr [__imp__printf (3A82B0h)]
003A354E add esp,0Ch
003A3551 cmp esi,esp
003A3553 call @ILT+295(__RTC_CheckEsp) (3A112Ch)
//第三题
//j = ++i+++i+++i; //编译犯错
//printf("i = %d,j = %d
",i,j);
//第四题
j = i+++j;
003A3558 mov eax,dword ptr [i]
003A355B add eax,dword ptr [j]
003A355E mov dword ptr [j],eax
003A3561 mov ecx,dword ptr [i]
003A3564 add ecx,1
003A3567 mov dword ptr [i],ecx
printf("i = %d,j = %d
",i,j);
003A356A mov esi,esp
003A356C mov ea甘蔗上火吗x,dword ptr [j]
003A356F push eax
003A3570 mov ecx,dword ptr [i]
003A3573 push ecx
003A3574 push offset string "i = %d,j = %d
" (3A5A00h)
003A3579 cal宝宝辅食l dword ptr [__imp__printf (3A82B0h)]
003A357F a夏利dd esp,0Ch
003A3582 cmp esi,esp
003A3584 call @ILT+295(__RTC_CheckEsp) (3A112Ch)
system("pause");
003A3589 push offset string "pause" (3A57B0h)
003A358E call @ILT+445(_system) 动态桌面壁纸(3A11C2h)
003A3593 add esp,4
return 0;
003A3596 xor eax,eax
}


首要咱们来剖析第1个题:j = (i++)+(i++)+(i++);

前面一些初始化我就不讲了,咱们直接对这句汇编进行剖析

 //榜首题
j = (i++)+(i++)+(i++);
003A34CC mov eax,dword ptr [i]
003A34CF add eax,dword ptr [i]
003A34D2 add eax,dword ptr [i]
003A34D5 mov dword ptr [j],eax
003A34D8 mov ecx,dword pt酒囊饭袋第三季r [i]
003A34DB add ecx,1
003A34DE mov dword ptr [i],ecx
003A34E1 mov edx,dword ptr [i]
003A34E4 add edx,1
003A34E7 mov dword ptr [i],edx
003A34EA mov eax,dword ptr [i]
003A34ED add eax,1
003A34F0 mov dword ptr [i],eax


这儿面实践就用了两条汇编指令mov和add:

mov指令:数据传输指令,用C言语的话讲便是赋值指令‘=’比方:mov AL,20H 兰州气候,你真的懂c言语和- -算符吗?-安博电竞竞猜-安博电竞相当于C言语便是 AL = 20H AL是寄存器

add指令:加法指令,用C言语的话讲便是一个复合赋值运算符指令‘+=’比方:add AX,8H 相当于C言语便是 AX += 8,再简单点便是AX = AX + 8

eax,ebx,ecx,edx,esi,edi,ebp,esp:这些都是通用寄存器,用C言语的话讲便是全局变量(可是这些寄存器又有特别用途,这儿不具体讲,感爱好能够百度)

dword:双字 便是四个字节

ptr:pointer 即指针

[]:里的数据是一个地址值,这个地址值指向一个双字型数据

比方:mov eax,dword ptr [12345678];把内存地址12345678中的双字型(32位)数据赋给eax,相当于C言语便是 exa = *12345678;

mov eax,dword ptr [i] ;把内存地址&i中的双字型(32)数据赋给exa,相当于C言语便是eax = i;

好了知道这些汇编指令就能够剖析了

003A34CC mov eax,dword ptr [i] ; 相当于C言语中 eax = i;由于i = 0,所以eax = 0 
003A34CF add eax,dword ptr [i] ; 相当于C言语中 eax = e卡通画ax + i; 由于i = 0,eax = 0,所以 eax = eax + i = 0
003A34D2 add eax,dword ptr [i] ; 相当于C言语中 eax = eax + i; 同上,eax = 0
003A34D5 mov dword ptr [j],eax ; 相当于C言语中 j = eax; 由于eax = 0,所以 j = 0


所曾经四条汇编指令履行完,j = 0,再往下面剖析

003A34D8 mov ecx,dword ptr [i] ; 相当于C言语中 ecx = i;由于i = 0,所以ecx = 0
003A34DB add ecx,1 ; 相当于C言语中 ecx = ecx + 1 ; 一切ecx = 1
003A34DE mov dword pt兰州气候,你真的懂c言语和- -算符吗?-安博电竞竞猜-安博电竞r [i],ecx ; 相当于C言语中 i = ecx;所以i = 1
003A34E1 mov edx,dword ptr [i] ;涪 相当于C言语中 edx = i;由于i = 1,所以edx = 1
003两只蝴蝶A34E4 add edx,1 ; 相当于C言语中 edx = edx + 1 ; 一切edx = 2
003A34E7 mov 兰州气候,你真的懂c言语和- -算符吗?-安博电竞竞猜-安博电竞dword ptr [i],edx ; 相当于C言语中 i = edx;所以i = 2
003A34EA mov eax,dword ptr [i] ; 相当于C言语中 eax = i;由于i = 2,所以eax = 2
003A34ED add eax,1 ; 相当于C言语中 eax = eax + 1 ; 一切eax = 3
003A34F0 mov dword ptr [i],eax ; 相当于C言语中 i = eax;所以i = 3


所以经过上面剖析,j = 0,i = 3;

这个剖析彻底和咱们注释的剖析是不相同的

好了咱们在剖析第2题(别忘了j = 0,i = 3)

 j = (++i)+(++i)+(++i);
003A3512 mov eax,dword ptr [i] ; 相当于C言语中 eax = i;由于i = 3,所以eax = 3
003A3515 add eax,1 ; 相当于C言语中 eax = eax + 1 ; 一切eax = 4
003A3518 mov dword ptr [i],eax ; 相当于C言语中 i = eax;所以i = 4
003A351B mov ecx,dword ptr [i] ; 相当于C言语中 ecx = i;由于i = 4,所以ecx = 4
003A351E add ecx,1 ; 相当于C言语中 ecx = ecx + 1 ; 一切ecx = 5
003A3521 mov dword ptr [i],ecx ; 相当于C言语中 i = ecx;所以i = 5
003A3524 mov edx,dword ptr [i] ; 相当于C言语中 edx = i;由于i = 5,所以edx = 5
003A3527 add edx,1 ; 相当于C言语中 edx = edx + 1 ; 一切edx = 6
003A352A mov dword ptr [i],edx ; 相当于C言语中 i = edx;所兰州气候,你真的懂c言语和- -算符吗?-安博电竞竞猜-安博电竞以i = 6
003A352D mov eax,dword ptr [i] 兰州气候,你真的懂c言语和- -算符吗?-安博电竞竞猜-安博电竞; 相当于C言语中 eax = i;由于i = 6,所以eax = 6
003A3530 add eax,dword ptr [i] ; 相当于C言语中 eax = eax + i ; 一切eax = 12
003A3533 add eax,dword ptr [i] ; 相当于C言语中 eax = eax + i ; 一切eax = 18
003A3536 mov dword ptr [j],eax ; 相当于C言语中 j = eax;由于eax = 18,所以j = 18


经过上面剖析,i = 6,j = 18

这个剖析彻底和咱们注释的剖析也是不相同的

好了咱们接着剖析第3题 (别忘了,i = 6)

j = ++i+++i+++i;

看看这个表达式是不是便是第2题的表达式去掉大括号啊,还真是啊

剖析进程:首要编译器读取榜首个字符‘+,这时编译器或许以为这是一个加法,也或许以为是一个自增运算符,所以编译器还会往后边读取,再读取一个字符‘+’,这时编译器就能够判别出来了,这是一个自增运算符,并且后边必定有一个变量在后边跟着,否则编译犯错,所以再读取一个字符‘i’,总结前面便是履行了一个“++i”,然后往下剖析,这时编译器往后边读取字符‘+’,这时编译器或许以为是加法,也或许以为是自增运算符,所以编译淄博市人力资源和社会保障网器还得往后边读取才干知道究竟是什么字符,这时编译器再读取一个字符‘老友趣薯片+’,这时编译器就能判别出来了,这是一个自增运算符,一起编译器也会报错,为什么会报错呢,由于前面++i,履行完是一个常数7,7后边又跟了自增运算符,相当于7++,这儿必定是过错的,由于自增或许自减运算符只能对变量履行,不能对常数,所以编译必定报错的

上面编译器处理的办法叫做“贪心法”,编译器经过贪心法处理表达式中的子表达式

有人或许以为你这些都是你瞎猜的,谁知道你剖析的对不对,又没有对应反汇编代码,所以pornos咱们在VS里边再加上一条句子

j = 7++;

看它是否和第3题的过错提示信息是否是相同,假如是相同的,就阐明咱们的剖析是对的




看见没,是相同的过错信息,所以咱们的剖析彻底正确,我一起也在ubuntu 10里边试了下,



gcc 提示信息:test.c:17: error: lvalue required as increment operand,中文意思:左值有必要是一个变量操作数

讲的有点累了,说的也比较烦琐,好了咱们再剖析下第4题(别忘了i = 6,j = 18)

j = i+++j;

这个表达式就会有两种成果:

第1种:j = (i++) + j;

第2种:j = i + (++j);

咱们这次选用两种办法解说:

榜首种:直接从C言语用“贪心法”剖析

第二种:从反汇编视点去剖析

榜首种:首要编译器读取i++,履行i++,然后在往后边读取字符‘+’这时编译以为或许是加法,也或许是自增运算符,所以还得往后边读取字符才干知道,再次读取一个字符‘j’,这时编译器就判别出来了,这是一个加法,所以编译器先履行,i++,然后在加上j,履行成果便是i = 7,j = 24,也便是它是按第1种状况履行的

第二种:从反汇编视点去剖析

003A3558 mov eax,dword ptr [i] ; 相当于C言语中 eax = i;由于i = 6,所以eax = 6

003A355B add eax,dword ptr [j] ; 相当于C言语中 eax = eax + j spend; 由于j = 18,一切eax = 24

003A355E mov dword ptr [j],eax ; 相当于C言语中 j = eax;所以j = 24

003A3561 mov ecx,dword ptr [i] ; 相当于C言语中 ecx = i;由于i = 6,所以ecx = 6

003A3564 add ecx,1 ; 相当于C言语中 ecx = ecx + 1 ; 一切ecx = 7

003A3567 mov dword ptr [i],ecx ; 相当于C言语中 i = ecx;所以i = 7

经过上面两种办法剖析,i = 7,j = 24

两种剖析办法里边具体履行细节仍是不相同的,反汇编必定是最具体的,最威望的,C言语仍是不行具体的,比方这道题里边,履行i++时,外表感觉,成果必定是6,履行完时i自身现已变成7了么?显然是看不出来的,只要经过反汇编咱们才知道,实践i自身值没有变成7,而是最终才变成7的

这儿好了,咱们再硬插一道第5题(否则还得写一篇博客)


看见没,第五题便是b = b/*p;p是指向整型a的变量,可是你假如不注意,输入结束,直接编译,编译犯错。

这时你在细心回去看下代码,发现b = b/*p;后边句子都是绿色了,都注释掉了,这是为什么,其实这是由于编译器把/*p当成‘/*’注释符了,所以后边全都注释掉了,那莫非就没有办法处理么?实践是能够处理的,你把除号后边加一个空格就能够了,b = b/ *p;

开端对上面进行总结:

1、++和--操作符在混合运算中的行为或许不同

2、++和--对应汇编指令不一定接连履行

3、在混合运算中,++和--的汇编指令或许被打断履行

4、编译器经过“贪心法”处理表达式中的子表达式

5、空格能够作为C言语中的一个完好符号的休止符

6、编译器读入空格后立即对之前读入的符号进行处理

这儿面还有许多关于++,--的一些坑

比方:printf("%d,%d ",i++,i++);

printf("%d,%d ",i++,i);

你以为上面输出会是相同的么?

i = 1;

j = ++i+i+++i;

printf("j = %d ",j); //j等于几,仍是说编译犯错

这些你都能够经过汇编去剖析

别的这是小编的大众号(MTCK2019)“”程序猿小龙“”给您们预备了学习材料

一些开发工具,接下来会预备更多的材料!有爱好能够重视一下哦!