C/C++|面试常碰到++p/p--问题到底结果是什么()
下面代码输出结果是什么?
int p = 5;
cout<<++p/p--<
是不是觉得面熟? ,看到这个题目的同学,想必其中很多人在笔试面试过程中都碰到过这个问题,但究竟结果是多少呢?
也许你心里面已经有了答案!
1?++p 结果是6, 6/5 再强制转成int, 那不就是1嘛!
结果真的是这样吗?下面是是实际运行的结果。
root@LAPTOP-GV31B6PG:~/code/cpp/tmp$ cat main.cpp
#include
using namespace std;
int main()
{
int p = 5;
cout<<++p/p--<
结果是0,是不是出乎意料,到底为什么呢?
下面带大家分析一下这个问题。自古:靠山,山会崩; 靠地,地会陷; 靠人,人会走。 人一辈子,靠天,靠地,不如靠自己; 求天,求地,不如求自己。是的,必须要自己弄懂才行,要弄懂就得多动手!
下面的分析会用到gdb,汇编的知识,因此先给大家科普一下基础知识,如果对此熟悉的请略过这一段。
项目 |
---|
AX――累加器(Accumulator),使用频度最高 |
AX――累加器(Accumulator),使用频度最高 |
BX――基址寄存器(Base Register),常存放存储器地址 |
CX――计数器(Count Register),常作为计数器 |
DX――数据寄存器(Data Register),存放数据 |
SI――源变址寄存器(Source Index),常保存存储单元地址 |
DI――目的变址寄存器(Destination Index),常保存存储单元地址 |
BP――基址指针寄存器(Base Pointer),表示堆栈区域中的基地址 |
SP――堆栈指针寄存器(Stack Pointer),指示堆栈区域的栈顶地址 |
IP――指令指针寄存器(Instruction Pointer),指示要执行指令所在存储单元的地址。IP寄存器是一个专用寄存器。 |
(gdb) disassemble /rm
Dump of assembler code for function main():
5{
0x000000000800088a <+0>:55push%rbp
0x000000000800088b <+1>:48 89 e5mov%rsp,%rbp
0x000000000800088e <+4>:48 83 ec 10sub$0x10,%rsp6int p = 5;
=> 0x0000000008000892 <+8>:c7 45 fc 05 00 00 00movl$0x5,-0x4(%rbp)7cout<<++p/p--<:83 45 fc 01addl$0x1,-0x4(%rbp)
0x000000000800089d <+19>:8b 4d fcmov-0x4(%rbp),%ecx
0x00000000080008a0 <+22>:8d 41 fflea-0x1(%rcx),%eax
0x00000000080008a3 <+25>:89 45 fcmov%eax,-0x4(%rbp)
0x00000000080008a6 <+28>:8b 45 fcmov-0x4(%rbp),%eax
0x00000000080008a9 <+31>:99cltd
0x00000000080008aa <+32>:f7 f9idiv%ecx
0x00000000080008ac <+34>:89 c6mov%eax,%esi
0x00000000080008ae <+36>:48 8d 3d 6b 07 20 00lea0x20076b(%rip),%rdi# 0x8201020 <_ZSt4cout@@GLIBCXX_3.4>
0x00000000080008b5 <+43>:e8 a6 fe ff ffcallq0x8000760 <_ZNSolsEi@plt>
0x00000000080008ba <+48>:48 89 c2mov%rax,%rdx
0x00000000080008bd <+51>:48 8b 05 0c 07 20 00mov0x20070c(%rip),%rax# 0x8200fd0
0x00000000080008c4 <+58>:48 89 c6mov%rax,%rsi
0x00000000080008c7 <+61>:48 89 d7mov%rdx,%rdi
0x00000000080008ca <+64>:e8 71 fe ff ffcallq0x8000740 <_ZNSolsEPFRSoS_E@plt>8return 0;
0x00000000080008cf <+69>:b8 00 00 00 00mov$0x0,%eax
---Type to continue, or q to quit---9}
0x00000000080008d4 <+74>:c9leaveq
0x00000000080008d5 <+75>:c3retqEnd of assembler dump.
(gdb)
- 命令
disassemble /rm
显示反汇编,/r
按照16进制显示数值,/m
显示源代码与汇编代码对应 - 前三句初始配置函数栈帧
0x000000000800088a <+0>:55push%rbp
0x000000000800088b <+1>:48 89 e5mov%rsp,%rbp
0x000000000800088e <+4>:48 83 ec 10sub$0x10,%rsp
- 这段揭示了真实面目
7cout<<++p/p--<:83 45 fc 01addl$0x1,-0x4(%rbp)
0x000000000800089d <+19>:8b 4d fcmov-0x4(%rbp),%ecx
0x00000000080008a0 <+22>:8d 41 fflea-0x1(%rcx),%eax
0x00000000080008a3 <+25>:89 45 fcmov%eax,-0x4(%rbp)
0x00000000080008a6 <+28>:8b 45 fcmov-0x4(%rbp),%eax
0x00000000080008a9 <+31>:99cltd
0x00000000080008aa <+32>:f7 f9idiv%ecx
【C/C++|面试常碰到++p/p--问题到底结果是什么()】
mov -0x4(%rbp),%ecx
将上一句自增的值复制到寄存器%ecx
, 注意到后面idiv除法运算时候这是作为分母值,再看分子lea -0x1(%rcx),%eax
将%rcx
值(也就是%ecx
)6 - 0x1即5赋值给 %eax
分子的5。这一步就是揭示了
++p/p--
的值也就是5/6取整后就是0,这下真相大白了。总结 通过以上分析,使用gdb调试功能很大程度上帮助我们分析一些看似不好理解的表达式。例如
++p/p--
那样,最终的计算实际是5/6的结果,取整输出后就是0。微信公众号
第一时间获取最新内容,欢迎关注微信公众号:「程序员阿广」。
文章图片
推荐阅读
- opencv|opencv C++模板匹配的简单实现
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- 2018国考外交部面试演讲不再难——只需把握好三点
- iOS面试题--基础
- c++基础概念笔记
- java|java 常用知识点链接
- 牛逼!C++开发的穿越丛林真人游戏,游戏未上线就有百万人气
- 年薪30万的Java架构师必会的springboot面试题
- linux笔记|linux 常用命令汇总(面向面试)
- 阿里Web前端面试题