1. ホーム
  2. c++

[解決済み] C++では、私は食べていないものにお金を払っているのでしょうか?

2022-04-23 11:03:47

質問

次のような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 ):

.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 ):

.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::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 を再度実行して改行し、フラッシュします。

    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

また、言語とライブラリの区別は必須です。

ちなみに、これはほんの一部です。自分が呼び出している関数に何が書いてあるかはわからない。