让我们考虑以下 C 和 C++ 中的 hello world 示例:
main.c
#include <stdio.h> int main() { printf("Hello world\n"); return 0; }
main.cpp
#include <iostream> int main() { std::cout<<"Hello world"<<std::endl; return 0; }
当我在 Godbolt 中将它们编译为汇编时,C 代码的大小只有 9 行(gcc -O3):
gcc -O3
.LC0: .string "Hello world" main: sub rsp, 8 mov edi, OFFSET FLAT:.LC0 call puts xor eax, eax add rsp, 8 ret
但是 C++ 代码的大小是 22 行 ( g++ -O3):
g++ -O3
.LC0: .string "Hello world" main: sub rsp, 8 mov edx, 11 mov esi, OFFSET FLAT:.LC0 mov edi, OFFSET FLAT:_ZSt4cout call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) mov edi, OFFSET FLAT:_ZSt4cout call std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&) xor eax, eax add rsp, 8 ret _GLOBAL__sub_I_main: sub rsp, 8 mov edi, OFFSET FLAT:_ZStL8__ioinit call std::ios_base::Init::Init() [complete object constructor] mov edx, OFFSET FLAT:__dso_handle mov esi, OFFSET FLAT:_ZStL8__ioinit mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev add rsp, 8 jmp __cxa_atexit
…这要大得多。
众所周知,在 C++ 中,您为所吃的东西付费。那么,在这种情况下,我要付出什么?
你付出的是调用一个沉重的图书馆(不像打印到控制台那么重)。你初始化一个ostream对象。有一些隐藏的存储。然后,您调用std::endlwhich 不是\n. 该iostream库可帮助您调整许多设置并将负担放在处理器而不是程序员身上。这就是你要付出的代价。
ostream
std::endl
\n
iostream
让我们回顾一下代码:
.LC0: .string "Hello world" main:
初始化 ostream 对象 + cout
sub rsp, 8 mov edx, 11 mov esi, OFFSET FLAT:.LC0 mov edi, OFFSET FLAT:_ZSt4cout call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
再次调用cout以打印新行并刷新
cout
mov edi, OFFSET FLAT:_ZSt4cout call std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&) xor eax, eax add rsp, 8 ret
静态存储初始化:
_GLOBAL__sub_I_main: sub rsp, 8 mov edi, OFFSET FLAT:_ZStL8__ioinit call std::ios_base::Init::Init() [complete object constructor] mov edx, OFFSET FLAT:__dso_handle mov esi, OFFSET FLAT:_ZStL8__ioinit mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev add rsp, 8 jmp __cxa_atexit
此外,区分语言和库也很重要。
顺便说一句,这只是故事的一部分。你不知道你调用的函数中写了什么。