前言
最近要准备面试,于是复习一下C++的语法。看起了C++ Primer这本书。
在看书上示例代码的时候,产生了一些疑惑。
话不多说,直接动手调试一遍吧。
示例代码
#include <iostream>
int main()
{
// prompt user to enter two numbers
std::cout << "Enter two numbers:"<< std::endl;
int v1 = 0, v2 = 0;
std::cin >> v1 >> v2;
std::cout << "The sum of " << v1 << " and " << v2
<< " is " << v1 + v2 << std::endl;
return 0;
}
一个很简单的求两数之和的程序
调试
编译之后,使用disassemble main 指令看一下对应的汇编代码。
0x0000555555555199 <+0>: push rbp
0x000055555555519a <+1>: mov rbp,rsp
0x000055555555519d <+4>: sub rsp,0x10
0x00005555555551a1 <+8>: mov rax,QWORD PTR fs:0x28
0x00005555555551aa <+17>: mov QWORD PTR [rbp-0x8],rax
0x00005555555551ae <+21>: xor eax,eax
0x00005555555551b0 <+23>: lea rsi,[rip+0xe4e] # 0x555555556005
0x00005555555551b7 <+30>: lea rdi,[rip+0x2ea2] # 0x555555558060 <_ZSt4cout@@GLIBCXX_3.4>
0x00005555555551be <+37>: call 0x555555555050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x00005555555551c3 <+42>: mov rdx,rax
0x00005555555551c6 <+45>: mov rax,QWORD PTR [rip+0x2e03] # 0x555555557fd0
0x00005555555551cd <+52>: mov rsi,rax
0x00005555555551d0 <+55>: mov rdi,rdx
0x00005555555551d3 <+58>: call 0x555555555060 <_ZNSolsEPFRSoS_E@plt>
0x00005555555551d8 <+63>: mov DWORD PTR [rbp-0x10],0x0
0x00005555555551df <+70>: mov DWORD PTR [rbp-0xc],0x0
0x00005555555551e6 <+77>: lea rax,[rbp-0x10]
0x00005555555551ea <+81>: mov rsi,rax
0x00005555555551ed <+84>: lea rdi,[rip+0x2f8c] # 0x555555558180 <_ZSt3cin@@GLIBCXX_3.4>
0x00005555555551f4 <+91>: call 0x555555555030 <_ZNSirsERi@plt>
0x00005555555551f9 <+96>: mov rdx,rax
0x00005555555551fc <+99>: lea rax,[rbp-0xc]
0x0000555555555200 <+103>: mov rsi,rax
0x0000555555555203 <+106>: mov rdi,rdx
0x0000555555555206 <+109>: call 0x555555555030 <_ZNSirsERi@plt>
0x000055555555520b <+114>: lea rsi,[rip+0xe06] # 0x555555556018
0x0000555555555212 <+121>: lea rdi,[rip+0x2e47] # 0x555555558060 <_ZSt4cout@@GLIBCXX_3.4>
0x0000555555555219 <+128>: call 0x555555555050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x000055555555521e <+133>: mov rdx,rax
0x0000555555555221 <+136>: mov eax,DWORD PTR [rbp-0x10]
0x0000555555555224 <+139>: mov esi,eax
0x0000555555555226 <+141>: mov rdi,rdx
0x0000555555555229 <+144>: call 0x555555555090 <_ZNSolsEi@plt>
0x000055555555522e <+149>: lea rsi,[rip+0xdef] # 0x555555556024
0x0000555555555235 <+156>: mov rdi,rax
0x0000555555555238 <+159>: call 0x555555555050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x000055555555523d <+164>: mov rdx,rax
0x0000555555555240 <+167>: mov eax,DWORD PTR [rbp-0xc]
0x0000555555555243 <+170>: mov esi,eax
0x0000555555555245 <+172>: mov rdi,rdx
0x0000555555555248 <+175>: call 0x555555555090 <_ZNSolsEi@plt>
0x000055555555524d <+180>: lea rsi,[rip+0xdd6] # 0x55555555602a
0x0000555555555254 <+187>: mov rdi,rax
0x0000555555555257 <+190>: call 0x555555555050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x000055555555525c <+195>: mov rdx,rax
0x000055555555525f <+198>: mov ecx,DWORD PTR [rbp-0x10]
0x0000555555555262 <+201>: mov eax,DWORD PTR [rbp-0xc]
0x0000555555555265 <+204>: add eax,ecx
0x0000555555555267 <+206>: mov esi,eax
0x0000555555555269 <+208>: mov rdi,rdx
0x000055555555526c <+211>: call 0x555555555090 <_ZNSolsEi@plt>
0x0000555555555271 <+216>: mov rdx,rax
0x0000555555555274 <+219>: mov rax,QWORD PTR [rip+0x2d55] # 0x555555557fd0
0x000055555555527b <+226>: mov rsi,rax
0x000055555555527e <+229>: mov rdi,rdx
0x0000555555555281 <+232>: call 0x555555555060 <_ZNSolsEPFRSoS_E@plt>
0x0000555555555286 <+237>: mov eax,0x0
0x000055555555528b <+242>: mov rcx,QWORD PTR [rbp-0x8]
0x000055555555528f <+246>: xor rcx,QWORD PTR fs:0x28
0x0000555555555298 <+255>: je 0x55555555529f <main()+262>
0x000055555555529a <+257>: call 0x555555555070 <__stack_chk_fail@plt>
0x000055555555529f <+262>: leave
0x00005555555552a0 <+263>: ret
整个程序就是输入两次分别存放到 rbp-0x10 和 rbp-0xc 中 并求和输出。
可以看到每调用一次输入输出,就是调用一次函数。
虽然书上说,调用std::cout << << 这种写法等价于调用两次std::cout,但却是调用的不同的函数(因为地址根本不一样)。
传string和传int值时,调用的函数也是不一样的。
大概看了一下std::endl的反汇编,调用流程如下 std::ctype -> std::cout -> std::ostream::flush