面试常碰到++p/p--问题到底结果是什么?
下面代碼輸出結(jié)果是什么?
int p = 5;
cout<<++p/p--<<endl;
是不是覺得面熟? 😄,看到這個題目的同學(xué),想必其中很多人在筆試面試過程中都碰到過這個問題,但究竟結(jié)果是多少呢?
也許你心里面已經(jīng)有了答案!
1?++p 結(jié)果是6, 6/5 再強制轉(zhuǎn)成int, 那不就是1嘛!
結(jié)果真的是這樣嗎?下面是是實際運行的結(jié)果。
root@LAPTOP-GV31B6PG:~/code/cpp/tmp$ cat main.cpp
#include <iostream>
using namespace std;int main()
{int p = 5;cout<<++p/p--<<endl;return 0;
}root@LAPTOP-GV31B6PG:~/code/cpp/tmp$ g++ -g main.cpp -o main
root@LAPTOP-GV31B6PG:~/code/cpp/tmp$ ./main
0
結(jié)果是0,是不是出乎意料,到底為什么呢?
下面帶大家分析一下這個問題。自古:靠山,山會崩;靠地,地會陷;靠人,人會走。 人一輩子,靠天,靠地,不如靠自己;求天,求地,不如求自己。是的,必須要自己弄懂才行,要弄懂就得多動手!
下面的分析會用到gdb,匯編的知識,因此先給大家科普一下基礎(chǔ)知識,如果對此熟悉的請略過這一段。
| 項目 |
|---|
| AX――累加器(Accumulator),使用頻度最高 |
| AX――累加器(Accumulator),使用頻度最高 |
| BX――基址寄存器(Base Register),常存放存儲器地址 |
| CX――計數(shù)器(Count Register),常作為計數(shù)器 |
| DX――數(shù)據(jù)寄存器(Data Register),存放數(shù)據(jù) |
| SI――源變址寄存器(Source Index),常保存存儲單元地址 |
| DI――目的變址寄存器(Destination Index),常保存存儲單元地址 |
| BP――基址指針寄存器(Base Pointer),表示堆棧區(qū)域中的基地址 |
| SP――堆棧指針寄存器(Stack Pointer),指示堆棧區(qū)域的棧頂?shù)刂?/td> |
| IP――指令指針寄存器(Instruction Pointer),指示要執(zhí)行指令所在存儲單元的地址。IP寄存器是一個專用寄存器。 |
(gdb) disassemble /rm
Dump of assembler code for function main():
5 {0x000000000800088a <+0>: 55 push %rbp0x000000000800088b <+1>: 48 89 e5 mov %rsp,%rbp0x000000000800088e <+4>: 48 83 ec 10 sub $0x10,%rsp6 int p = 5;
=> 0x0000000008000892 <+8>: c7 45 fc 05 00 00 00 movl $0x5,-0x4(%rbp)7 cout<<++p/p--<<endl;0x0000000008000899 <+15>: 83 45 fc 01 addl $0x1,-0x4(%rbp)0x000000000800089d <+19>: 8b 4d fc mov -0x4(%rbp),%ecx0x00000000080008a0 <+22>: 8d 41 ff lea -0x1(%rcx),%eax0x00000000080008a3 <+25>: 89 45 fc mov %eax,-0x4(%rbp)0x00000000080008a6 <+28>: 8b 45 fc mov -0x4(%rbp),%eax0x00000000080008a9 <+31>: 99 cltd0x00000000080008aa <+32>: f7 f9 idiv %ecx0x00000000080008ac <+34>: 89 c6 mov %eax,%esi0x00000000080008ae <+36>: 48 8d 3d 6b 07 20 00 lea 0x20076b(%rip),%rdi # 0x8201020 <_ZSt4cout@@GLIBCXX_3.4>0x00000000080008b5 <+43>: e8 a6 fe ff ff callq 0x8000760 <_ZNSolsEi@plt>0x00000000080008ba <+48>: 48 89 c2 mov %rax,%rdx0x00000000080008bd <+51>: 48 8b 05 0c 07 20 00 mov 0x20070c(%rip),%rax # 0x8200fd00x00000000080008c4 <+58>: 48 89 c6 mov %rax,%rsi0x00000000080008c7 <+61>: 48 89 d7 mov %rdx,%rdi0x00000000080008ca <+64>: e8 71 fe ff ff callq 0x8000740 <_ZNSolsEPFRSoS_E@plt>8 return 0;0x00000000080008cf <+69>: b8 00 00 00 00 mov $0x0,%eax
---Type <return> to continue, or q <return> to quit---9 }0x00000000080008d4 <+74>: c9 leaveq0x00000000080008d5 <+75>: c3 retqEnd of assembler dump.
(gdb)
- 命令
disassemble /rm顯示反匯編,/r按照16進制顯示數(shù)值,/m顯示源代碼與匯編代碼對應(yīng) - 前三句初始配置函數(shù)棧幀
0x000000000800088a <+0>: 55 push %rbp 0x000000000800088b <+1>: 48 89 e5 mov %rsp,%rbp0x000000000800088e <+4>: 48 83 ec 10 sub $0x10,%rsp
- 這段揭示了真實面目
7 cout<<++p/p--<<endl;0x0000000008000899 <+15>: 83 45 fc 01 addl $0x1,-0x4(%rbp)0x000000000800089d <+19>: 8b 4d fc mov -0x4(%rbp),%ecx0x00000000080008a0 <+22>: 8d 41 ff lea -0x1(%rcx),%eax0x00000000080008a3 <+25>: 89 45 fc mov %eax,-0x4(%rbp)0x00000000080008a6 <+28>: 8b 45 fc mov -0x4(%rbp),%eax0x00000000080008a9 <+31>: 99 cltd0x00000000080008aa <+32>: f7 f9 idiv %ecx
mov -0x4(%rbp),%ecx 將上一句自增的值復(fù)制到寄存器%ecx, 注意到后面idiv除法運算時候這是作為分母值,再看分子lea -0x1(%rcx),%eax 將%rcx值(也就是%ecx)6 - 0x1即5賦值給 %eax 分子的5。
這一步就是揭示了++p/p--的值也就是5/6取整后就是0,這下真相大白了。
總結(jié)
通過以上分析,使用gdb調(diào)試功能很大程度上幫助我們分析一些看似不好理解的表達式。例如++p/p--那樣,最終的計算實際是5/6的結(jié)果,取整輸出后就是0。
微信公眾號
第一時間獲取最新內(nèi)容,歡迎關(guān)注微信公眾號:「程序員阿廣」。
總結(jié)
以上是生活随笔為你收集整理的面试常碰到++p/p--问题到底结果是什么?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: docker run 或者 docker
- 下一篇: 离线安装Visual Studio Co