web-dev-qa-db-ja.com

C ++の初期割り当てがCの初期割り当てよりもはるかに大きいのはなぜですか?

同じコードを使用する場合、コンパイラーを(CコンパイラーからC++コンパイラーに)変更するだけで、割り当てられるメモリー量が変更されます。これがなぜなのかよくわかりませんし、もっと理解したいと思っています。これまでのところ、私が得た最良の応答は「おそらくI/Oストリーム」です。これはあまり説明的ではなく、C++の「使用しないものにお金を払わない」という側面について疑問に思います。

私はそれぞれClangおよびGCCコンパイラー、バージョン7.0.1-8および8.3.0-6を使用しています。私のシステムは、Debian 10(Buster)で稼働しています。ベンチマークは、Valgrind Massifを介して行われます。

#include <stdio.h>

int main() {
    printf("Hello, world!\n");
    return 0;
}

使用されるコードは変更されませんが、Cとしてコンパイルする場合もC++としてコンパイルする場合も、Valgrindベンチマークの結果が変更されます。ただし、値はコンパイラー間で一貫しています。プログラムのランタイム割り当て(ピーク)は次のようになります。

  • GCC(C):1,032バイト(1 KB)
  • G ++(C++):73,744バイト、(〜74 KB)
  • Clang(C):1,032バイト(1 KB)
  • Clang ++(C++):73,744バイト(〜74 KB)

コンパイルには、次のコマンドを使用します。

clang -O3 -o c-clang ./main.c
gcc -O3 -o c-gcc ./main.c
clang++ -O3 -o cpp-clang ./main.cpp
g++ -O3 -o cpp-gcc ./main.cpp

Valgrindの場合、valgrind --tool=massif --massif-out-file=m_compiler_lang ./compiler-lang各コンパイラおよび言語で、その後ms_printピークを表示します。

ここで何か間違ったことをしていますか?

135
Rerumu

ヒープの使用は、C++標準ライブラリから取得されます。起動時に内部ライブラリが使用するメモリを割り当てます。リンクしない場合は、CバージョンとC++バージョンの間にゼロの違いがあるはずです。 GCCとClangを使用すると、次を使用してファイルをコンパイルできます。

 g ++ -Wl、-as-needed main.cpp 

これにより、未使用のライブラリに対してリンクしないようにリンカーに指示します。サンプルコードでは、C++ライブラリは使用されていないため、C++標準ライブラリとリンクしないでください。

Cファイルでこれをテストすることもできます。でコンパイルする場合:

 gcc main.c -lstdc ++ 

Cプログラムを作成した場合でも、ヒープの使用量が再表示されます。

ヒープの使用は明らかに、使用している特定のC++ライブラリの実装に依存します。あなたの場合、それはGNU C++ライブラリ、 libstdc ++ です。他の実装では、同じ量のメモリを割り当てられないか、メモリをまったく割り当てない可能性があります。 LLVM C++ライブラリ( libc ++ )は、たとえば、少なくともLinuxマシンでは、起動時にヒープの割り当てを行いません。

 clang ++ -stdlib = libc ++ main.cpp 

ヒープの使用は、それに対してまったくリンクしないことと同じです。

(コンパイルが失敗した場合、libc ++はおそらくインストールされていません。通常、パッケージ名には「libc ++」または「libcxx」が含まれています。)

148
Nikos C.

GCCもClangもコンパイラではありません。実際にはツールチェーンドライバプログラムです。つまり、コンパイラ、アセンブラ、およびリンカを呼び出します。

CまたはC++コンパイラでコードをコンパイルすると、同じアセンブリが生成されます。アセンブラーは同じオブジェクトを生成します。違いは、ツールチェーンドライバーが2つの異なる言語のリンカーに異なる入力を提供することです:異なるスタートアップ(C++では、名前空間レベルで静的またはスレッドローカルストレージ期間を持つオブジェクトのコンストラクターとデストラクターを実行するためのコードが必要であり、スタックのためのインフラストラクチャが必要ですたとえば、例外処理中のアンワインドをサポートするフレーム)、C++標準ライブラリ(名前空間レベルで静的ストレージ期間のオブジェクトもあります)、およびおそらく追加のランタイムライブラリ(たとえば、スタックアンワインドインフラストラクチャを備えたlibgcc)。

要するに、フットプリントの増加を引き起こしているのはコンパイラではなく、C++言語を選択して使用することを選択したもののリンクです。

C++には「使用した分だけ支払う」という哲学があるのは事実ですが、この言語を使用することで料金を支払うことができます。言語の一部(RTTI、例外処理)を無効にできますが、C++は使用しなくなります。別の回答で述べたように、標準ライブラリをまったく使用しない場合は、ドライバにそれを除外するよう指示することができます(--Wl、-as-needed)が、機能を使用しない場合C++またはそのライブラリの場合、なぜプログラミング言語としてC++を選択しているのですか?

15
Stephen M. Webb