なぜCはそんなに速いのか、なぜ他の言語はそれほど速くも速くもないのですか?[閉まっている]


208

StackOverflowポッドキャストを聞いていると、ジャブは「本物のプログラマ」がCで書いていることを思い起こし、Cは「マシンに近い」ため、はるかに高速です。以前のアサーションを別の投稿に残して、Cが他の言語よりも高速になることを可能にする特別な点は何ですか?または別の言い方をすると:他の言語がCと同じくらい高速に実行されるバイナリにコンパイルできないようにする方法は何ですか?


6
これについて話した特定の番組をリストアップできますか?それを聞きたいです。
Giovanni Galbo、

2
この質問への回答がどれほどひどいか(ほとんどの回答はコンパイル済み言語と解釈済み言語の基本的な違いを無視しているなど、JITやだやだやだやだについて知っています)、そして自分の好きな言葉を「守る」立場を取っている人々(FORTRAN少年のニーズ)に本当に驚いていますピルを服用する)。
ティムリング

アセンブリ言語を忘れないでください。アセンブリで組み立てられたexeよりも高速でコンパクトなものはありません。アセンブリはほぼ純粋なバイナリなので、最速の言語に偏りがありません。
KKZiomek

3
Cは光の速度と相対性のため、最速ですか?
Taraviya 2017年

もちろん、Cが最速のプログラム言語であることは間違いです。FORTHの速度に近いプログラム言語はありません。FORTHは核爆弾を誘発するために使用されます。これはほとんどの衛星のプログラム言語であり、国際宇宙ステーションやCERN、ITERの主要なプログラム言語です。Microsoft C(異なるバージョン)とFORTHの速度を比較していました。ヨーンからC ...
Scoobeedo Cool

回答:


200

Cについて特別なことはそれほど多くありません。それが高速である理由の1つです。

ガベージコレクション動的型付け、およびプログラマーによるプログラムの作成を容易にするその他の機能をサポートする新しい言語。

問題は、アプリケーションのパフォーマンスを低下させる追加の処理オーバーヘッドがあることです。Cにはそれがありません。つまり、オーバーヘッドはありませんが、プログラマーは、メモリリークを防ぐためにメモリを割り当てて解放する必要があり、変数の静的型付けを処理する必要があります。

とはいえ、Java(Java仮想マシンを使用)や.NET(共通言語ランタイムを使用)などの多くの言語やプラットフォームは、ネイティブマシンコードを生成するジャストインタイムコンパイルなどの登場により、長年にわたってパフォーマンスが向上しています。より高いパフォーマンスを達成するためのバイトコード。


3
ガベージコレクションは、手動のメモリ管理よりも高速である可能性があります(存続期間の短いプログラムや大量のメモリの場合)。GCはシンプルで高速な割り当てを可能にし、プログラムはものの割り当てを解除する時間を費やしません。
Kornel

2
Cプログラムは通常、必要に応じてメモリの割り当てと割り当て解除を行います。これは非効率的です。優れたVMは、大きなチャンクで割り当てと割り当て解除を行うため、多くの場合、パフォーマンスが大幅に向上します。
skaffman 2009年

60
「ハード」であることを除けば、Cプログラムが同じチャンク割り当てとガベージコレクションを実行するのを妨げるものは何もありません。
ephemient 2009年

非常によく言われましたが、ロブアレンが言ったように、CもJavaまたは.NETよりも抽象化が少ないため、翻訳が少なくなります(ジャストインタイム(JIT)コンパイルが原因で最近はあまり当てはまりません)
Gab Royer

5
ポルノ、手動管理、賢明な割り当ては、正しく使用すると常にどのGCシステムよりも優れており、多くの注意が払われています。使用パターンについて絶対的な知識があり、GCはそうではありません。さらに、GCシステムはオーバーヘッドを追加します
Ion Todirel

89

Cデザイナーが行ったトレードオフがあります。つまり、安全性よりも速度を優先することにしました。Cはしません

  • 配列インデックスの境界を確認する
  • 初期化されていない変数値を確認します
  • メモリリークをチェックする
  • nullポインター逆参照をチェックする

配列にインデックスを付ける場合、Javaでは、仮想マシンでのメソッド呼び出し、境界チェック、その他の健全性チェックが必要です。それは正当であり、絶対に問題ありません。なぜなら、それが原因で安全性が追加されるからです。しかし、Cでは、ごく些細なことでさえ安全にはなりません。たとえば、Cはmemcpyにコピーする領域が重複しているかどうかを確認するように要求しません。それはだていない大企業のアプリケーションをプログラミングするための言語として設計されています。

ただし、これらの設計上の決定はC言語のバグではありません。コンパイラーやライブラリーの作成者がコンピューターからあらゆるパフォーマンスを引き出すことができるため、これらは仕様によるものです。Cの根拠となるドキュメントで説明されているCの精神は次のとおりです。

Cコードは移植できません。プログラマに真に移植可能なプログラムを作成する機会を与えることを目指しましたが、委員会はCを「高レベルのアセンブラ」として使用することを排除するために、プログラマに移植性のある書き込みを強制したくありませんでした:マシン固有の書き込み機能コードはCの長所の1つです。

C精神を維持します。委員会は、Cの伝統的な精神を維持するための主要な目標として維持しました。Cの精神には多くの側面がありますが、本質は、C言語の基礎となる基本原則のコミュニティの感情です。Cの精神のいくつかの側面は、次のようなフレーズで要約できます。

  • プログラマーを信頼してください。
  • プログラマーが必要なことをするのを妨げないでください。
  • 言語は小さくシンプルにしてください。
  • 操作を行う1つの方法のみを提供します。
  • ポータブルであることが保証されていない場合でも、高速にしてください。

最後のことわざには少し説明が必要です。効率的なコード生成の可能性は、Cの最も重要な長所の1つです。非常に単純な操作のように見えるものに対してコードの爆発が起こらないようにするために、多くの操作は、ターゲットマシンのハードウェアがそれを行う方法ではなく、一般的な抽象ルール。マシンが何をするかというこの意欲の例は、式で使用するcharオブジェクトの拡張を制御するルールに見ることができます。charオブジェクトの値が符号付きまたは符号なしの量に拡張されるかどうかは、通常、より多くのバイト操作に依存します。ターゲットマシンで効率的です。


51
Cは激しくクラッシュすることにより、nullポインタderefをチェックします:-)。また、スタックフレームとデータをめちゃくちゃにすることにより、範囲外の配列インデックスと初期化されていない変数を時々チェックします。残念ながら、実行時にこれらをチェックします。
paxdiablo 2009年

18
Cは安全ではないとは言えません。これは、あなたが示唆しているように聞こえます。それはあなたがばかでないと仮定します。銃を下に向けて自分の足を撃つと、Cは喜んで義務付け、それを許可します。それは必ずしも悪いことではありません。
ボブ・ソマーズ

19
@ボブ:その通り。危険なことをすることができるのでCは安全ではないと言うことは、崖から車を運転することができるので車は安全ではないと言うようなものです。Cは運転をしている人と同じくらい安全です(しかし、そこには危険なドライバーがたくさんいます)。
Robert Gamble、

5
ボブ、バッファオーバーランのようなバグを作ることは、あなたが馬鹿であるという意味ではありません。それはあなたがまだ人間であることを意味します。CとC ++は悪くないことを私は理解しています(私はそれらに非常に似ています)。
ヨハネスシャウブ-litb 2009年

4
@ JohannesSchaub-litb Cは、大規模なアプリケーションプログラミングに最適です。プロジェクトをHello Worldよりも大きくするのが難しい場合、問題は言語ではなくプログラマにあります...

75

Cで何かを構築するのに1か月を費やして0.05秒で実行し、1日をJavaで同じものを書いて0.10秒で実行する場合、Cは本当に高速ですか?

しかし、あなたの質問に答えるために、Cコードを「よく」書くことの一部には、マシンに近いレベルで手動の最適化を行うことが含まれるため、よく書かれた Cコードは、他の言語のよく書かれたコードよりも速く実行されます。

コンパイラーは確かに非常に賢いですが、手で管理されたアルゴリズムと競合するコードを創造的に生み出すことはまだできていません(「手」は優れた Cプログラマーに属している想定しています)。

編集:

「Cで書いていて、最適化については考えていません」というコメントがたくさんあります。

しかし、この投稿から特定の例をとると:

Delphiでこれを書くことができます:

function RemoveAllAFromB(a, b: string): string;
var
  before, after :string;
begin
  Result := b;
  if 0 < Pos(a,b) then begin
    before := Copy(b,1,Pos(a,b)-Length(a));
    after := Copy(b,Pos(a,b)+Length(a),Length(b));
    Result := before + after;
    Result := RemoveAllAFromB(a,Result);  //recursive
  end;
end;

そしてCIでこれを書いてください:

char *s1, *s2, *result; /* original strings and the result string */
int len1, len2; /* lengths of the strings */
for (i = 0; i < len1; i++) {
   for (j = 0; j < len2; j++) {
     if (s1[i] == s2[j]) {
       break;
     }
   }
   if (j == len2) {  /* s1[i] is not found in s2 */
     *result = s1[i]; 
     result++; /* assuming your result array is long enough */
   }
}

しかし、Cバージョンにはいくつの最適化がありますか?Delphiバージョンでは考えられない実装に関する多くの決定を行います。文字列はどのように実装されますか?Delphiには表示されません。Cでは、charと呼ばれるASCII整数の配列へのポインターになることを決定しました。Cでは、キャラクターの存在を1つずつテストします。Delphiでは、Posを使用します。

そして、これはほんの小さな例です。大規模なプログラムでは、Cプログラマーは数行のコードごとにこの種の低レベルの決定を行わなければなりません。その結果、手作りで最適化された実行可能ファイルが作成されます。


45
しかし、公平に言うと、Cで1か月かかること、Javaで1日しかかからない、実行に0.05秒しかかからないこと(つまり、小さなプログラム)はそれほど多くありません。
dreamlax 2009年

12
私は長年Cでプログラミングしてきましたが、ヒントにしたような最適化を行う必要はほとんどありません。私は多くのプログラムをC(主にPerlから)に移植しましたが、通常、10倍の速度向上とメモリ使用量の大幅な削減が手作業でコーディングされた最適化なしで行われています。
Robert Gamble、

1
もちろん、既存の設備がないためにCでのプログラミングにはかなり時間がかかる可能性があるものもあります。そのため、コンピューターのパフォーマンスと(特に)プログラマーのパフォーマンスとの間のトレードオフであり、すべてをCでプログラムするわけではありません。
Robert Gamble、

4
Javaまたは.NETプログラムが起動するよりも短い時間で数千行のデータを処理するC ++プログラムを作成しました。それは私がより近代的な言語に持っている欲求不満の一つです。Cは、最小限のランタイム要件を必要とする無駄のないプログラムに最適です。PowerBasicもそのために最適です。
bruceatk 2009年

35
Cで1か月かかり、Javaで作成されたプログラムで1日しかかからないプログラムの2倍の速さのプログラムは、価値がないと言っていますか?そのプログラムが1日に5億回以上実行する必要がある場合はどうなりますか?2倍高速であることは非常に重要です。それが数千または数百万のCPUで実行される場合、2倍のパフォーマンスを達成するための開発の追加月のコスト削減は莫大になります。基本的に、開発プラットフォームを選択する前に、展開の規模を把握しておく必要があります。
nicerobot 14年

49

私はまだそれを見ていなかったので、私はそれを言います 。他のほとんどすべてがCで書かれているため、Cはより高速になる傾向があります

JavaはCに基づいて構築され、PythonはC(またはJava、.NETなど)に基づいて構築され、Perlはその他などです。OSはCで記述され、仮想マシンはCで記述され、コンパイラはCで記述されます。インタプリタはCで書かれています。いくつかはまだアセンブリ言語で書かれていますが、さらに高速になる傾向があります。ますます多くのものが別の何かで書かれています。それ自体がCで書かれています。

他の言語(アセンブリではない)で記述する各ステートメントは、通常、Cのいくつかのステートメントの下に実装され、ネイティブマシンコードにコンパイルされます。これらの他の言語は、Cよりも高いレベルの抽象化を実現するために存在する傾向があるため、Cで必要なこれらの追加のステートメントは、安全性の追加、複雑さの追加、およびエラー処理の提供に重点が置かれる傾向があります。それらはしばしば良いものですが、コストがかかり、その名前はスピードサイズです。

個人的に、私は文字通り何十もの言語で利用可能なスペクトルのほとんどを網羅して書いており、私は個人的にあなたがヒントとする魔法を求めてきました:

どうすればケーキも食べられますか?どうすればお気に入りの言語で高レベルの抽象化を試してから、スピードを上げるためにCの要点に落とすことができますか?

数年の研究の後、私の答えはPython(on C)です。あなたはそれを見てみたいかもしれません。ちなみに、Pythonからアセンブリーにドロップダウンすることもできます(特別なライブラリーからのマイナーな助けが必要です)。

一方、不正なコードはどの言語でも記述できます。したがって、C(またはアセンブリ)コードは自動的に高速にはなりません。同様に、一部の最適化トリックでは、高水準言語コードの一部を生のCのパフォーマンスレベルに近づけることができます。しかし、ほとんどのアプリケーションでは、プログラムはほとんどの時間を人やハードウェアで待機するため、違いは実際には問題になりません。

楽しい。


10
これは、JITコンパイル言語には実際には適用されません。それは、私のC#がILにコンパイルされていて、マシンコードにコンパイルされているCに翻訳されているようなものではありません。いいえ、ILはJITでコンパイルされています。その時点では、JITの実装言語は関係ありません。マシンコードを生成するだけです。
Jon Skeet、

3
神が伝説のジョンスキートに質問することを禁じていますが、生成されるマシンコードがCではなくC#用であることは完全に関連しているようです。そのため、「より高いレベル」であり、より多くの機能を持ち、安全性チェックがあります。したがって、「同等の」Cよりも遅い
ロブウィリアムズ

3
@ジョン:私は同じようなことを言おうとしていたが、.NETライブラリのコアコンポーネントの多くは実際にはCで実際に記述されているため、Cの速度制限があるため、ポイントは実際にはある程度有効です。これが将来どのように変わるかを見るのは興味深いでしょう。
Konrad Rudolph、

1
これは間違った方法のようです。他の言語のコンパイラ/インタープリタ/ vmsは頻繁にではありますが、常に(少なくとも最下位層では)cで書かれているため、cはかなり高速です(多くの場合、最高速です)。
ローマンA.テイチャー

2
この答えは正しくありません。上記で指摘したように、これはJIT言語には適用されませんが、独自のコンパイラーを備えた言語にも適用されません(非常に多くの努力が払われた場合、最新のCコンパイラーよりも高速なコードが生成される可能性があります)。残っている他の言語のクラスはインタプリタ言語だけであり、それらはC自体で書かれているだけでなく、インタプリタがどのようにスライスされていても、またインタプリタがアセンブリで書かれていたとしても、インタプリタのオーバーヘッドがあるため、Cより遅くはありません、 は巨大。
Score_Under

38

そこにはたくさんの質問があります-ほとんど私が答える資格がない質問です。しかし、この最後のものについて:

他の言語がCと同じくらい高速に実行されるバイナリにコンパイルできないようにする方法は何ですか?

つまり、抽象化です。

Cは機械語から1レベルまたは2レベルの抽象化レベルにすぎません。Javaおよび.Net言語は、アセンブラーから少なくとも3レベルの抽象化レベルにあります。PythonとRubyについてはよくわかりません。

通常、プログラマーのおもちゃ(複雑なデータ型など)が多ければ多いほど、機械語から遠くなり、より多くの翻訳を行う必要があります。

私はあちこち離れていますが、それが基本的な要点です。

更新 -------この投稿には、より詳細なコメントが含まれています。


3
技術的には、Javaと.Netは、実行されるマシンのマシン言語から無限に抽象化されています。これらはVMで実行されます。JITを使用しても、元のコードを大幅にマッサージして、ネイティブマシンコードに似たものを取得する必要があります。
jmucchiello 2009年

1
.netコードはVMでは実行されません。実行しているプロセッサプラットフォーム(32ビットx86、64ビットx86、またはIA64)でネイティブ命令として実行されます。
ロバートC.バース

11
@Robert:.net VMを使用します。.netコードは、VMによって実行されるバイトコードにコンパイルされます。VMは、実行時にバイトコードをネイティブ命令に変換します。
Robert Gamble、

3
それはだ非常に Javaや他のオブジェクト指向言語の抽象化は、プロセッサの命令セットに影響を与えていることに注意することが重要。新しいプロセッサには、Java VMがこれらの最適化を認識して使用している場合にJavaをより高速に実行するための命令があります。大きくはありませんが、役に立ちます。
アダムデイビス


35

Cのコストモデルが透過的であるため、Cが高速であることはそれほど多くありません。Cプログラムが遅い場合、多くのステートメントを実行することにより、明らかに遅いです。Cでの操作のコストと比較すると、オブジェクト(特にリフレクション)または文字列に対する高レベルの操作には、明白ではないコストがかかる場合があります。

一般にCと同じくらい高速なバイナリにコンパイルされる2つの言語は、標準ML(MLtonコンパイラーを使用)とObjective Camlです。ベンチマークゲームを確認すると、バイナリツリーなどの一部のベンチマークでは、OCamlバージョンがCよりも高速であることがわかります(MLtonエントリは見つかりませんでした)。それは言う通り、ゲームであり、結果は多くの場合、人々がコードの調整に費やした努力の量を反映しています。


明らかに高価ではないコードを任意の言語で書くことが可能です。それは...いくつかの言語では、あなたが最初にフォースのLispの内側の変種を書いたりする必要があるだけのことだ
ドナル・フェローズ

また、RustはベンチマークでCに一致します。
スターク

18

Cは常に速いとは限りません。

Cは、たとえばModern Fortranよりも低速です。

多くの場合、CはJavaよりも低速です。(特に、JITコンパイラがコードを実行した後)

Cはポインターのエイリアシングを発生させます。これは、いくつかの適切な最適化が不可能であることを意味します。特に複数の実行ユニットがある場合、これによりデータフェッチが停止します。わー

一部のCPUファミリ(特にPIC!)でポインタ演算が実際に遅くなると仮定すると、セグメント化されたx86で大きなものを吸収していました。

基本的に、ベクトルユニットまたは並列化コンパイラーを入手すると、Cは悪臭を放ち、最新のFortranはより高速に実行されます。

サンク(実行ファイルをオンザフライで変更)のようなCプログラマのトリックは、CPUプリフェッチストールを引き起こします。

あなたはドリフトを得るのですか?

そして、私たちの親友であるx86は、最近の実際のCPUアーキテクチャとほとんど関係のない命令セットを実行します。シャドーレジスタ、ロードストアオプティマイザ、すべてCPU内。したがって、Cは仮想金属に近くなります。本当の金属、インテルはあなたに見せません。(歴史的にVLIW CPUはちょっとしたバストだったので、それほど悪くないかもしれません。)

高性能DSP(たぶんTI DSP?)でCでプログラムする場合、コンパイラーは複数の並列実行ユニット間でCを展開するためにいくつかのトリッキーなことをしなければなりません。したがって、その場合、Cは金属に近くありませんが、コンパイラーに近く、プログラム全体を最適化します。変。

最後に、一部のCPU(www.ajile.com)は、ハードウェアでJavaバイトコードを実行します。CはそのCPUでPITAを使用します。


1
サンクがCで最後に書かれたのはいつですか?最新のx86は、主にRISC設計へのインターフェースですが、VLIWとはほとんど関係がありません...
Calyth

7
あなたの投稿の多くはC99の存在を無視しています。また、多くのC / C ++コンパイラーは、C99制限キーワード(ポインターのエイリアスがないことを保証)を拡張機能として提供しています。
エヴァンテラン

誰もがCWE / SANSトップ25をフォロー/移行しており、Cでの新しいデザインの作成を避けていると思います。グリーンフィールドCはなく、C99はほとんどありません。
Tim Williscroft、2009年

2
cが現代のフォーテンベリーより遅い場合の例を示していただけますか?
Adam

Cコンパイラーが最高のFortranコンパイラーと非常によく競合した時代があったかどうかはわかりません。もちろん、FORTRAN 77(66は言うまでもありません)で記述したくないコードはたくさんありますが、最近のFortran標準はますます快適になっています。
tfb 2016

11

他の言語がCと同じくらい高速に実行されるバイナリにコンパイルできないようにする方法は何ですか?

何もない。Javaや.NET言語などの最近の言語は、パフォーマンスよりもプログラマの生産性を重視しています。ハードウェアは今日安いです。また、中間表現へのコンパイルは、セキュリティ、移植性などの多くのボーナスを提供します。.NETCLRは、さまざまなハードウェアを利用できます。たとえば、SSE命令セットを使用するためにプログラムを手動で最適化/再コンパイルする必要はありません。


ここで移植性について議論します。本当に移植可能なコードが必要な場合は、他の言語ではなくCで記述します。約25のオペレーティングシステムで実行されているコードがあります。dosとthreadXから始まり、Linux / XPで終了すると、それを実行できる別の言語が表示されます:)
Ilya

1
@Ilya同意しない。Cで移植不可能なコードを書くのも同じくらい簡単です。64ビットに移植するのがどれほど大変だったか見てみましょう。適切なバイトコードインタープリタがあれば、バイトコード言語はプラットフォーム全体で機能します。
Calyth、2009年

1
@IIya、移植可能なCコードは規則ではなく例外です。異なるハードウェア/ソフトウェアプラットフォーム間でCコードを移植し、それが悪夢であることを知っていました。
aku

PCワードでもそうではありません。c / c ++で書かれたクロスプラットフォームアプリケーションのほとんどを実際に見てください。組み込み低レベル開発の場合、他にケースはありません。Cは事実上最も移植性の高い言語です。
イリヤ

@aku->悪いコードを移植することは災いかもしれません。ADVANCE-Cで移植可能なコードを書くことは最良の選択です。C ++はオプションだと思いますが、組み込みプラットフォームに行くと、いつもまともなCコンパイラが見つかります。
Ilya、

8

主な要因は、静的に型付けされた言語であり、マシンコードにコンパイルされていることです。また、低水準言語であるため、通常、ユーザーが指示しないことは何も行いません。

これらは頭に浮かぶいくつかの他の要因です。

  • 変数は自動的に初期化されません
  • 配列の境界チェックなし
  • 未チェックのポインタ操作
  • 整数オーバーフローチェックなし
  • 静的に型付けされた変数
  • 関数呼び出しは静的です(関数ポインターを使用しない限り)
  • コンパイラー作成者は、最適化コードを改善するために多くの時間を費やしてきました。また、人々は最高のパフォーマンスを得るためにCでプログラミングするので、コードを最適化する必要があります。
  • 言語仕様の一部は実装定義であるため、コンパイラーは最適な方法で自由に処理を実行できます

ほとんどの静的型付き言語は、Cと同じかそれより高速にコンパイルできますが、特にポインタのエイリアスなどのためにCができないと仮定できる場合はなおさらです。


C低レベル?私はそれがJavaと比較して今は相対的な意味であると思いますが、アセンブリーとは比較しません。良いポスト、考えさせられた。
マーク

あなたは正しい、それは間違いなく相対的です。つまり、これは「マシンに近い」ので、メモリ管理や配列サイズの追跡などを行うのに役立ちません。
Matthew Crumley、

2
Cは低水準言語です。Cは常に低水準言語でした。Cコードをアセンブラーに手作業で簡単に変換できます。
ロバートC.バース

2
@Robert:Cは、アセンブリ(非常に一般的)と比較して、高級言語と見なされていました。現在使用されている大多数の言語と比較して、低レベル言語と見なされています。
Robert Gamble、

正直なところ、これは非常に偏った答えです。ほぼすべてのCプログラマーは境界チェックなどを行いますが、CはC ++よりもはるかに高速です。
MarcusJ

8

アセンブリ言語も言語であることを忘れていたと思います:)

しかし真剣に、Cプログラムは、プログラマーが何をしているかを知っている場合にのみ高速になります。同じ仕事をする他の言語で書かれたプログラムよりも実行速度が遅いCプログラムを簡単に書くことができます。

Cの方が高速である理由は、Cがこのように設計されているためです。コンパイラーがコードを最適化するのに役立つ多くの「低レベル」のことを行うことができます。または、プログラマーがコードを最適化する責任を負うとしましょう。しかし、それはしばしばかなりトリッキーでエラーが発生しやすくなります。

他の言語は、すでに述べた他の言語と同様に、プログラマーの生産性により重点を置いています。プログラマーの時間は、マシンの時間よりもはるかに高価であると一般的に信じられています(昔でも)。したがって、プログラマがプログラムの実行時間ではなく、プログラムの作成とデバッグに費やす時間を最小限に抑えることは、理にかなっています。そのためには、多くのことが自動化されているため、プログラムを高速化するためにできることを少し犠牲にします。


3
ただし、Cで1回、Assemblyで1回プログラムを作成した場合、コンパイラーはあなたより賢いので、Cバージョンの方がおそらく高速です。
mk12 2012

7

ほとんどの場合、すべてのC命令はごく少数のアセンブラー命令に対応しています。あなたは本質的に高レベルのマシンコードを書いているので、プロセッサが行うほとんどすべてのものを制御できます。C ++など、他の多くのコンパイル済み言語には、見た目よりもはるかに多くのコードに変換できる単純な命令がたくさんあります(仮想関数、コピーコンストラクターなど)。JavaやRubyなどのインタープリター型言語には、別のレイヤーがあります。表示されない指示-仮想マシンまたはインタープリター。


そして、これらの高級言語のいくつかは、そもそも追加した残骸のほとんどを取り除くことができることを誇りにしています。C ++でのコピーの省略、戻り値の最適化、移動の構築/割り当てなど。
cmaster-

つまり、コードから生成されるアセンブリ命令の数がすべてです。高レベルコードの1行あたりのアセンブリ命令が多いほど、パフォーマンスが低下しますか?
ENDEESA

これは単純化しすぎかもしれませんが、アセンブリ命令の数とプログラム速度の間には直接的な関係があります。プロセッサが各命令を実行するための最小時間があります。記述している命令の数を簡単に理解できる言語であるIMHOは、より効率的なコードの記述に役立ちます。(分岐やキャッシュミスなど、他のプロセッサ時間コストがありますが、それでも抽象化が少ないと、CPUの動作を明確にするのに役立ちます)。
AShelly

7

多くの人が長い間それを言ってきたことを知っていますが、

Cは(あなたにとって)少ないのでより高速です。


この。C.の精神に非常に真
cmaster -モニカ復活

7

C ++は平均して高速です(当初はCのスーパーセットでしたが、いくつかの違いはあります)。ただし、特定のベンチマークについては、より高速な別の言語がよくあります。

https://benchmarksgame-team.pages.debian.net/benchmarksgame/

fannjuch-redux Scalaで最速だった

n-bodyそしてfasta速くエイダでいました。

spectral-norm Fortranで最速でした。

reverse-complementmandelbrotおよびpidigitsATSで最速でした。

regex-dna JavaScriptで最速でした。

chameneou-redux 最も速かったのはJava 7です。

thread-ring ハスケルで最速だった。

残りのベンチマークは、CまたはC ++で最も高速でした。


「それはCのスーパーセットであるように、」 -いいえ、C ++はない Cのスーパーセット
PP

1
extern "C"C ++があることとは何の関係もありませんスーパーセット C.の
PP

2
これはsystem("bash script.sh");、どのbashスクリプトでも機能すると言っているようなもので、Cはbashのスーパーセットです。extern "C"名前マングリングのために、C ++でCリンケージを提供します。XをYのスーパーセットとして呼び出すことは、Yで実行できるすべてのことをXでも実行できることを意味しますが、これはC ++には当てはまりません。Cでは有効であるがC ++では無効な言語構成要素がかなりあります。
PP

1
@PP C ++標準にbashは、使用可能なコマンドラインプログラムを義務付けるものはありません。サポートしておく必要があるbashのバージョン/仕様が含まれている場合、それをスーパーセットと見なします。
Peter Lawrey

1
C ++コードではないCコードを書くのは簡単です。例えばstruct foo { int: this; }; typedef float foo;
Jasen

6

これらの回答の多くは、Cが(一般的または特定のシナリオで)高速である、または高速ではない理由の正当な理由を示しています。それは否定できない:

  • 他の多くの言語は、私たちが当たり前と思っている自動機能を提供しています。たとえば、境界チェック、実行時の型チェック、自動メモリ管理などは無料ではありません。少なくともいくつかあります私たちが、あるいは考えても、実現-ながら、これらの機能を使用するコードを書いていないことがあり、これらの機能に関連したコストが。
  • ソースからマシンへのステップは、他の言語ではCの場合ほど直接ではないことがよくあります。
  • OTOHは、コンパイルされたCコードが他の言語で記述された他のコードよりも高速に実行されると言うのは、常に真であるとは限らない一般化です。反例は簡単に見つけられます(または考案されます)。

それにもかかわらず、他にも、Cと他の多くの言語の比較パフォーマンスに、他のどの要素よりも大きな影響を与えることに気付いたことがあります。ウィットするには:

他の言語では、実行速度が遅いコードを簡単に記述できることがよくあります。多くの場合、それは言語のデザイン哲学によってさえ励まされます。結果:Cプログラマーは、不要な操作を実行しないコードを書く可能性が高くなります。

例として、単一のメインウィンドウが作成される単純なWindowsプログラムを考えます。Cバージョンは、WNDCLASS[EX]に渡される構造を入力し、RegisterClass[Ex]呼び出しCreateWindow[Ex]てメッセージループに入ります。高度に簡略化された簡略化されたコードは次のとおりです。

WNDCLASS wc;
MSG      msg;

wc.style         = 0;
wc.lpfnWndProc   = &WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = hInstance;
wc.hIcon         = NULL;
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName  = NULL;
wc.lpszClassName = "MainWndCls";

RegisterClass(&wc);

CreateWindow("MainWndCls", "", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
             CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

while(GetMessage(&msg, NULL, 0, 0)){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

C#での同等のプログラムは、1行のコードでもかまいません。

Application.Run(new Form());

この1行のコードは、約20行のCコードが実行したすべての機能を提供し、エラーチェックなど、省略したいくつかの機能を追加します。(典型的なCプロジェクトで使用されるライブラリと比較して)豊富で充実したライブラリは私たちにとって多くの作業を行い、私たちには、見た目が悪いが裏で多くのステップを含む多くのコードスニペットを書く時間を解放しました。

しかし、簡単で迅速なコードの膨張を可能にする豊富なライブラリーは、私の趣旨ではありません。私の小さなワンライナーが実際に実行されるときに実際に何が起こるかを調べ始めると、私のポイントはより明白になります。楽しみのために、Visual Studio 2008以降で.NETソースアクセス有効にし、上記の簡単な1行に進んでください。あなたが遭遇する楽しい小さな宝石の1つは、次のゲッター内のこのコメントですControl.CreateParams

// In a typical control this is accessed ten times to create and show a control.
// It is a net memory savings, then, to maintain a copy on control.
// 
if (createParams == null) {
    createParams = new CreateParams(); 
} 

10回。保存されているものの合計とほぼ同等の情報WNDCLASSEX構造とどのように渡されますCreateWindowExから取得されControlたクラスの10時間前にそれがで保存されているWNDCLASSEX構造とに渡さRegisterClassExCreateWindowEx

全体として、この非常に基本的なタスクを実行するために実行される命令の数は、C#よりもC#の方が2〜3桁多くなります。これの一部は、機能が豊富なライブラリの使用によるものです。必要なことを正確に実行し、それ以上は実行しない単純なCコード。しかし、その一部は、.NETフレームワークのモジュール化されたオブジェクト指向の性質が、手続き型のアプローチによって回避されることが多い多くの実行の繰り返しに役立っているという事実によるものです。

C#や.NET Frameworkを選択するつもりはありません。モジュール化、一般化、ライブラリ/言語機能、OOPなどが悪いことだとも言っていません。私は開発の大部分をCで、後でC ++で、そして最近ではC#で行っていました。同様に、C以前は、ほとんどアセンブリを使用していました。そして、私の言語が「高く」なる各ステップで、私はより短い時間でより良い、より保守しやすく、より堅牢なプログラムを書きます。ただし、実行速度は少し遅くなる傾向があります。


2
これはAPIの問題であり、言語の問題ではありません。
アラファンギオン

1
@アラファンギオン:私はあなたの言っていることが理解できますが、それは要点を逃しています。機能豊富なライブラリは、機能豊富な言語によって有効化されます(ある意味で、要求されます)。そしてそれは単なるライブラリではありません。ライブラリは、言語の一般的な使用例にすぎません。任意の言語の一般的なアプリケーションコードは、通常、その言語で一般的に使用されるライブラリに類似しています。それは本当に言語によって育まれた考え方です。たとえば、オブジェクト指向言語は通常、オブジェクトの割り当て、構築、破棄、および割り当て解除に、OOPサポートの少ない言語よりも多くの時間を費やします。
Pダディ

与えられた言語の選択は一般に特定のプラットフォームとライブラリを意味することを認めます。そのため、私はそのコメントを(読者がより気付くように)作成した理由ですが、(たとえば)WindowsでのC ++の使用はLinux上のC ++とは非常に異なった獣であり、Android上のC ++でもまた異なります。もう1つの例はPythonです。CPython、Jython、PyPy、IronPythonがあり、すべて非常に異なるライブラリを使用しています。
Arafangion、

しかし、これらのPythonのいずれかを使用すると、開発者は特定の方法でアプリケーションを作成する傾向があります。たとえば、テキストファイルの読み取りと書き込みを行い、読み取ったデータを使用して新しいオブジェクトを作成できます。一方、Cでは、開発者は構造体の配列を一度だけ割り当て、バイナリファイルからそれらの構造体を読み書きする可能性が高くなります。もちろん、これは、私が考え方について述べようとしている点を説明しようとする、単なる不自然な例です。
Pダディ

6

おそらくJavaを除いて、他のコンパイラーよりもCコンパイラーに多くの労力が費やされたという事実について誰も言及しなかったと思います。

Cは、すでに述べた多くの理由で、他のほとんどの言語よりも非常に最適化可能です。したがって、他の言語コンパイラに同じ量の労力が費やされたとしても、Cはおそらくトップに立つでしょう。

少なくとも1つの候補言語があり、努力を重ねればCよりも最適化できるため、より高速なバイナリを生成する実装を見ることができます。デジタルマーズDについて考えています。Cよりも最適化される可能性のある言語を作成者が作成することに注意を払ったからです。この可能性のある他の言語があるかもしれません。しかし、どの言語でも、最高のCコンパイラよりも数パーセント以上高速なコンパイラを実現できるとは思えません。私は間違っていたいです。

本当の「ぶら下がり果物」は、人間が最適化するのが簡単になるように設計された言語であると思います。熟練したプログラマーであれば、どの言語でも高速に処理できますが、これを実現するために、とんでもないことをしたり、不自然な構造を使用したりする必要がある場合があります。常に努力が必要ですが、優れた言語は、プログラムの記述方法に厳密にこだわる必要なく、比較的高速なコードを生成する必要があります。

最悪の場合のコードが高速になる傾向があることも(少なくとも私にとって)重要です。JavaはCと同じかそれより速いというWeb上の「証明」は数多くありますが、それはチェリーピッキングの例に基づいています。私はCの大ファンではありませんが、Cで書いたものはすべてうまくいくことを知っています。Javaを使用すると、「おそらく」速度の15%以内、通常は25%以内で実行されますが、場合によってはそれよりはるかに悪いこともあります。それが同じくらい高速であるか、数パーセント以内である場合は通常、とにかくCで大幅に最適化されているライブラリコードに費やされている時間のほとんどが原因です。


5

これは実際には永続的な虚偽のビットです。Cプログラムの方が高速であることが多いのは事実ですが、これは必ずしも当てはまるわけではありません。特にCプログラマーがあまり上手ではない場合はなおさらです。

人々が忘れがちな大きな大きな穴の1つは、プログラムが何らかのGUIプログラムでのユーザー入力など、何らかのIOをブロックしなければならない場合です。これらの場合、データの処理速度ではなく、データの受信速度によって制限されるため、使用する言語は問題ではありません。この場合、C、Java、C#、さらにはPerlを使用しているかどうかはそれほど重要ではありません。データが入ってくるよりも速く行くことはできません。

もう1つの重要な点は、ガベージコレクションを使用し、適切なポインターを使用しないことで、仮想マシンが他の言語では利用できない多くの最適化を行えるようになることです。たとえば、JVMはオブジェクトをヒープ上で移動させてデフラグすることができます。これにより、テーブルで検索するのではなく、次のインデックスを簡単に使用できるため、将来の割り当てがはるかに速くなります。最近のJVMは、実際にメモリの割り当てを解除する必要もありません。代わりに、GCを実行するときにライブオブジェクトを移動するだけで、デッドオブジェクトから消費されたメモリは基本的に無料で回復されます。

これはまた、Cについて興味深い点をもたらします。C++の場合はなおさらです。「必要ないのなら、お金を払わない」という設計哲学のようなものがあります。問題は、あなたがそれを望めば、結局それを鼻から払ってしまうことです。たとえば、Javaのvtable実装はC ++実装よりもはるかに優れている傾向があるため、仮想関数呼び出しははるかに高速です。一方、Javaで仮想関数を使用する以外に選択肢はなく、それでもいくらかコストがかかりますが、仮想関数を多く使用するプログラムでは、コストが削減されます。


1
「Javaのvtable実装はC ++実装よりもはるかに優れている傾向があるため、仮想関数呼び出しははるかに高速です。」いったいどうすればMOV EAX [ECX]より速く進むことができますか CALL [EAX + someindex]; ?検索せずに関数を呼び出せない限り、これはかなり最適に見えます。
Frans-Willem

@Frans-JITコンパイラ(Java HotSpotなど)は、特定のオブジェクトが常に特定の型であると判断した場合、vtableルックアップをインライン化できます。C ++は、コンパイル時に同じ情報を知っている場合にもこれを行いますが、この最適化は、x86マシン命令よりもJavaバイトコードを使用した方が簡単です。
トム

6
@James-「I / Oによってパフォーマンスの問題が軽減される」と主張しても、「Cは他の言語よりも高速である」というステートメントは無効になりません。それは明白な穴ではなく、それはストローマンの議論です。
トム

Cの文字列処理(および標準のCライブラリも)を例として使用した方がよいでしょう。これは、Cが不十分な領域だからです。他のほとんどの言語は、単純化した開始コードを使用しても、よりよく機能します。
ドナルフェロー

@DonalFellows mem *関数は、一部のタスクではstr *関数よりも高速ですが、注意が必要な場合、文字列の処理は効率的です。特定のベンチマークを考えていますか?
Jasen 2017年

4

それは、ツールやライブラリーほど言語についてではありません。Cで使用できるライブラリとコンパイラは、新しい言語よりもはるかに古くなっています。あなたはこれが彼らを遅くすると思うかもしれませんが、反対です。

これらのライブラリは、処理能力とメモリが非常に貴重なときに作成されました。それらは、まったく機能するために非常に効率的に書かれなければなりませんでした。Cコンパイラの開発者も、さまざまなプロセッサ向けにあらゆる種類の巧妙な最適化に取り組む長い時間を費やしてきました。Cの成熟度と幅広い採用により、同じ時代の他の言語に比べて大きな利点があります。また、Cが必要とするほどの生のパフォーマンスを重視しない新しいツールよりも、Cに速度上の利点があります。


4

抽象化の欠如は、Cをより速くするものです。出力ステートメントを書くと、何が起こっているのか正確にわかります。Javaで出力ステートメントを記述する場合、クラスファイルにコンパイルされ、抽象化の層を導入する仮想マシンで実行されます。言語の一部としてのオブジェクト指向機能の欠如により、生成されるコードが少なくなるため、速度も向上します。Cをオブジェクト指向言語として使用している場合は、クラス、非侵害などのすべてのコーディングを行っています。これは、コード量と、書き込みのみを必要とするパフォーマンスペナルティを備えたすべての人にとって十分に一般化されたものを作成することを意味しますあなたが仕事を成し遂げるために必要なもの。


4

古い「Javaが解釈されるため、C / C ++ Javaよりも高速である必要がある」という神話は驚くべきものです。数年前の記事最近の記事があり、これが必ずしも常にそうであるとは限らない理由や概念を説明しています。

現在の仮想マシンの実装(ちなみに、JVMだけでなく)は、プログラムの実行中に収集された情報を利用して、さまざまな手法を使用して、実行時にコードを動的に調整できます。

  • 頻繁にメソッドをレンダリングしてコードを機械加工し、
  • 小さなメソッドのインライン化
  • ロックの調整

そしてコードが実際に何をしているかを知ること、およびコードが実行されている環境の実際の特性に基づいて、他のさまざまな調整を行います。


私は、Javaは、生のパフォーマンスの面ではるかに近いCにそれを持って、最後の数年間で大幅なパフォーマンス向上を行いましたが、それはそれがあったという事実ダウン生きるためにしばらく時間がかかることに同意するものとしますので、低速のためのとても長いし。しかし、とにかく誰がJavaについて話していましたか?
Robert Gamble、

JavaはOPによって参照される「他の言語」ですが、そうではありませんか?
ロバートC.バース

@Robert:「他の言語」、複数形、C以外の特定の言語についての言及なし。どのようにして「Java」をそこから読みますか?
Robert Gamble、

@Roberd:私が質問に遭遇する前に投稿された回答のいくつかは、Java(または多くの場合、インタープリターまたはVMを介して実装される他の言語)について話していました。
joel.neely 2009年

3
@Joel-ターゲットハードウェアがわかっている場合、JVMが実行時に実行できるほとんどの最適化は、CまたはC ++でプロファイルに基づく最適化を使用して行うこともできます。これは大きな違いをもたらし、CとC ++は実行中に「学習」する必要がないため、通常はCとC ++が先頭に戻ります。
トム

4

最速で実行されるコードは、注意深く手作りされたマシンコードです。アセンブラはほぼ同じです。どちらも非常に低レベルであり、処理を行うには多くのコードを書く必要があります。Cはアセンブラより少し上です。実際のマシンでは非常に低いレベルで物事を制御する能力はまだありますが、アセンブラよりも速くて簡単に書くための十分な抽象化があります。C#やJAVAなどの他の言語は、より抽象的です。アセンブラーとマシンコードは低水準言語と呼ばれますが、C#とJAVA(およびその他の多く)は高水準言語と呼ばれます。Cは中級言語と呼ばれることもあります。


あなたの答えを読んでいる間、段落全体のたった2つの単語が、磁石が金属を引っ張っているように、私の目を引きつけていました。単語はJAVAで、段落の2倍です。決して:-)すべて大文字で書かれた前にそれを見ていない、そしてそれは良い探しています
Sнаđошƒаӽ

3

誰かの言葉を使わないでください。コードのパフォーマンスが重要な部分で、Cと選択した言語の両方の逆アセンブリを確認してください。 Visual Studioの実行時に逆アセンブリウィンドウを見るだけで、逆アセンブルされた.Netを確認できると思います。windbgを使用してJavaにトリッキーな場合は可能ですが、.Netでそれを行う場合、問題の多くは同じです。

必要がなければCで書くのは好きではありませんが、C以外の言語の速度を宣伝するこれらの回答で行われた主張の多くは、Cで同じルーチンを逆アセンブルするだけで脇に置くことができると思います選択した上位レベルの言語で、特にパフォーマンスが重要なアプリケーションで一般的であるように大量のデータが含まれる場合。Fortranはその専門分野の例外かもしれませんが、わかりません。Cより高いレベルですか?

初めて、JITされたコードとネイティブコードを比較して、.NetコードがCコードと同等に実行できるかどうかのすべての質問を解決しました。追加レベルの抽象化とすべての安全性チェックにはかなりのコストがかかります。同じコストがJavaに適用される可能性がありますが、私の言葉にとらわれず、パフォーマンスが重要な場所で試してください。(誰でも、JITされたJavaについて十分に知っていて、コンパイルされたプロシージャをメモリ内で見つけることができますか?確かに可能です)


2

1)他の人が言ったように、Cはあなたのためにもっと少ないことをします。初期化変数、配列境界チェック、メモリ管理などはありません。他の言語のこれらの機能は、Cが費やさないメモリとCPUサイクルを消費します。

2)Cは抽象化されていないため、より高速であると答えるのは、正解の半分に過ぎないと思います。技術的に言えば、言語Xの「十分に高度なコンパイラ」を使用している場合、言語XはCの速度に近づくか、または同等にすることができます。Cとの違いは、(アーキテクチャコースを受講した場合)素朴なコンパイラでさえまともな仕事をすることができるアセンブリ言語に直接。Pythonのようなものでは、可能性のあるオブジェクトのタイプを予測し、その場でマシンコードを生成するための非常に高度なコンパイラが必要です。Cのセマンティクスは非常に単純で、単純なコンパイラで十分に機能します。


2

古き良き時代には、コンパイルと解釈の2種類の言語しかありませんでした。

コンパイルされた言語は、「コンパイラ」を利用して言語構文を読み取り、それを同一のアセンブリ言語コードに変換します。解釈された言語はいくつかの異なるスキームを使用しましたが、基本的に言語構文は中間形式に変換され、コードを実行するための環境である「インタプリタ」で実行されました。

したがって、ある意味では、コードとマシンの間に別の「レイヤー」、つまりインタープリターがありました。また、コンピューターの場合と同様に、より多くのリソースが使用されます。通訳者は、より多くの操作を実行する必要があったため、速度が遅くなりました。

最近では、Javaのように、コンパイラーとインタープリターの両方を使用してそれらを動作させるハイブリッド言語が増えています。複雑ですが、JVMは古いインタープリターよりも高速で洗練されており、はるかに最適化されているため、単なるコンパイル済みコードに近いパフォーマンス(時間の経過)のはるかに優れた変化に対応できます。もちろん、新しいコンパイラーには、より洗練された最適化の秘訣があり、以前よりもはるかに優れたコードを生成する傾向があります。しかし、ほとんどの最適化では、ほとんどの場合(常にではありませんが)、すべての状況で常に高速であるとは限らないような、ある種のトレードオフが行われます。他のすべてと同様に、無料のものは何もないため、オプティマイザはどこかから自慢を得る必要があります(多くの場合、ランタイムCPUを節約するためにコンパイル時CPUを使用します)。

Cに戻ると、これは単純な言語であり、かなり最適化されたアセンブリにコンパイルして、ターゲットマシンで直接実行できます。Cでは、整数をインクリメントすると、CPUでのアセンブラーのステップが1つしかない可能性が高くなりますが、Javaではそれよりもはるかに多くなる可能性があります(ガベージコレクションも含まれる可能性があります)。 -)Cは、マシンに非常に近い(アセンブラが最も近い)抽象化を提供しますが、それを実現するためには、さらに多くの作業を行う必要があり、保護が不十分で、使いやすく、エラーが発生しにくいです。他のほとんどの言語は、より高い抽象化を提供し、基礎となる詳細の多くを処理しますが、高度な機能と引き換えに、実行するためにより多くのリソースを必要とします。いくつかのソリューションを一般化すると、より幅広いコンピューティングを処理する必要があります。

ポール。


「Cでは、整数をインクリメントすると、CPUのアセンブラーのステップが1つしかない可能性が高くなります」正確には当てはまりません。この整数がCPUレジスタにない場合は、メモリからフェッチしてインクリメントし、メモリに書き戻すためのマシンコードが必要です。Javaコードを実行するときにもほぼ同じことが起こります。そして、「++ i」がそれ自体でGCサイクルをトリガーする理由がわかりません。
quant_dev 2009年

@quant_dev: "メモリからフェッチして、インクリメントして、書き戻す必要があります..."。多分そうでないかもしれません。たとえば、x86には、メモリ内のデータを操作する命令があります。++i「add [ebp-8]、1」にコンパイルされる場合があります。Paulが言ったように、フェッチ、インクリメント、ストアがまだ行われていないことは言うまでもありませんが、これはCPUによって処理され、1つの命令にすぎません。
Pダディ

...パフォーマンスのPOVとは関係ありません。これは、1つの命令にすぎない可能性がありますが、データがCPUに到着するまで待機する必要があるためです。キャッシュミスなど。
quant_dev 2009年

いいえ、私はそれが無関係であるとは言いません。通常、1つのCPU命令は、複数のCPU命令よりも少ないコードバイトを占有し、コードセグメントのキャッシュパフォーマンスが向上します。また、1つのCPU命令はCPUのパイプライン上で占有するスペースが少なく、複数のステップ(フェッチ、インクリメント、ストア)を(おそらく並行して)別々のパイプラインステージで処理できます。実際、パイプライン上の他の操作と統合できる場合、操作の一部がスキップされることもあります。たとえば、値の保存は、同じ値の後続のロードと融合できます。
Pダディ

2

ホットスポット最適化事前にコンパイルされたメタアルゴリズム、およびさまざまな形式の並列処理などの高度な最適化手法は別として、言語の基本的な速度は、一般的な操作をサポートするために必要な暗黙的な舞台裏の複雑さと強く相関します。内部ループ内で指定されます

おそらく最も明白なのは、間接メモリ参照の有効性チェックnullです。たとえば、配列境界に対するポインタのチェックやインデックスのチェックなどです。ほとんどの高級言語はこれらのチェックを暗黙的に実行しますが、Cは実行しません。ただし、これは必ずしもこれらの他の言語の基本的な制限ではありません -十分に賢いコンパイラは、何らかの形のループ不変コードモーションを介して、アルゴリズムの内部ループからこれらのチェックを削除できる場合があります。

Cのより基本的な利点(および同様の程度で密接に関連するC ++)は、スタックベースのメモリ割り当てに大きく依存しています。これは、割り当て、割り当て解除、およびアクセスが本質的に高速です。C(およびC ++)では、プライマリコールスタックを使用して、プリミティブ、配列、および集約(struct/class)。

Cは動的に割り当てる機能を提供しますが、任意のサイズと存続期間のメモリ(いわゆる「ヒープ」を使用)を提供しますが、デフォルトではそう(代わりにスタックが使用されます)。

魅惑的なことに、他のプログラミング言語のランタイム環境内でCメモリ割り当て戦略を複製することが可能な場合があります。これはasm.jsによって実証されており、CまたはC ++で記述されたコードをJavaScriptのサブセットに変換し、ネイティブに近い速度でWebブラウザー環境で安全に実行できます。


余談ですが、CおよびC ++が他のほとんどの言語よりも速度を優れているもう1つの領域は、ネイティブの機械語命令セットとシームレスに統合する機能です。この注目すべき例は、SIMDコンパイラ組み込み関数の(コンパイラとプラットフォームに依存する)可用性です。これにより、今やほぼユビキタスな並列処理ハードウェアを利用するカスタムアルゴリズムの構築がサポートされます。レベルのレジスタ割り当てはコンパイラによって管理されます)。


1
Cのこのメモリ割り当ての利点の一部は、おそらく他の言語でも巧妙なコンパイラによって再現できます(ここを参照)。ただし、これは特に構造的に非常に難しい、特にプリミティブ以外のデータ型の場合はそうだという印象を受けます。 この投稿では、Javaの最適化としてスタックに割り当てることができる、エスケープしないオブジェクトの考え方について触れています。
nobar

2

一部の言語が速い理由と遅い言語についての回答をリンクで見つけました。これにより、CまたはC ++が他の言語より速い理由が明らかになることを願っています。Cよりも速い他の言語もありますが、私たちはできません。それらすべてを使用してください。いくつかの説明-

Fortranが依然として重要である大きな理由の1つは、Fortranが高速であるためです。Fortranで記述された数値計算ルーチンは、他のほとんどの言語で記述された同等のルーチンよりも高速になる傾向があります。この領域でFortranと競合している言語(CおよびC ++)は、このパフォーマンスと競合するために使用されます。

これは疑問を投げかけます:なぜですか?C ++とFortranが高速化する理由と、JavaやPythonなどの他の一般的な言語よりも優れている理由は何ですか。

解釈とコンパイルプログラミング言語を分類して定義するには、彼らが奨励するプログラミングのスタイルと提供する機能に応じて、多くの方法があります。パフォーマンスを見ると、インタープリター言語とコンパイル言語の最大の違いが1つあります。

分割は難しくありません。むしろ、スペクトルがあります。一方には、Fortran、C、およびC ++を含む従来のコンパイル言語があります。これらの言語には、プログラムのソースコードをプロセッサが使用できる実行可能な形式に変換する個別のコンパイル段階があります。

このコンパイルプロセスにはいくつかのステップがあります。ソースコードが分析され、解析されます。タイプミスやスペルミスなどの基本的なコーディングの誤りは、この時点で検出できます。解析されたコードは、メモリ内表現を生成するために使用されます。これも、誤りを検出するために使用できます。今回は、存在しない関数の呼び出しや、テキストの文字列に対する算術演算の実行など、意味上の誤りを検出します。

このインメモリ表現は、実行可能コードを生成するコードジェネレーターを駆動するために使用されます。生成されたコードのパフォーマンスを改善するためのコード最適化は、このプロセス内のさまざまな時点で実行されます。高レベルの最適化はコード表現で実行でき、低レベルの最適化はコードジェネレーターの出力で使用されます。

実際にコードを実行すると、後で発生します。コンパイルプロセス全体を使用して、実行可能なものを作成します。

反対側には通訳がいます。インタープリターにはコンパイラーと同様の解析ステージが含まれますが、これは直接実行するために使用され、プログラムはすぐに実行されます。

最も単純なインタープリターは、その言語がサポートするさまざまな機能に対応する実行可能コードを内部に持っています。そのため、数値を追加したり、文字列を結合したりするなど、特定の言語の機能を備えています。コードを解析するときに、対応する関数を検索して実行します。プログラムで作成された変数は、名前をデータにマップする何らかのルックアップテーブルに保持されます。

インタープリタースタイルの最も極端な例は、バッチファイルやシェルスクリプトのようなものです。これらの言語では、実行可能コードは多くの場合、インタープリター自体に組み込まれていませんが、個別のスタンドアロンプ​​ログラムに組み込まれています。

では、なぜこれがパフォーマンスに影響を与えるのでしょうか?一般に、間接参照の各層はパフォーマンスを低下させます。たとえば、2つの数値を加算する最も速い方法は、両方の数値をプロセッサのレジスタに入れ、プロセッサのadd命令を使用することです。これが、コンパイルされたプログラムが実行できることです。変数をレジスターに入れ、プロセッサーの命令を利用できます。しかし、解釈されたプログラムでは、同じ追加を行うには、追加する値をフェッチするために変数のテーブルで2つのルックアップが必要で、その後、追加を実行する関数を呼び出す必要があります。その関数は、コンパイルされたプログラムが実際の加算を実行するために使用するものと同じプロセッサ命令を非常によく使用する可能性がありますが、命令が実際に使用できるようになる前のすべての余分な作業により、処理が遅くなります。

詳細を知りたい場合は、ソースを確認してください


1

一部のC ++アルゴリズムはCよりも高速であり、他の言語でのアルゴリズムまたは設計パターンの一部の実装はCよりも高速である場合があります。

Cは高速であると人々が言っ​​た後、他の言語について話をするとき、彼らは一般的にCのパフォーマンスをベンチマークとして使用しています。


2
「一部のC ++アルゴリズムはCよりも高速です」は意味がありません。「C ++アルゴリズム」はCで作成でき、その逆も可能です。アルゴリズムは言語に依存しません。C ++は基本的にCに機能を追加します-これらの新機能はどれもより高速なアルゴリズムにつながりません(ただし、おそらくそれらはより簡単に記述できます)。
ジョセフガービン

1
古典的な非難はstd :: sortアルゴリズムです。std:: sortはCのどのソートアルゴリズムよりも高速です。Cで同じパフォーマンスを得る唯一の方法は、必要な場所にハードコードするか、マクロを使用することです。コンパイラーは最適化する情報が少なくなります。
アラファンギオン2009

1

最新の最適化コンパイラーを使用すると、純粋なCプログラムがコンパイル済みの.netコードよりもはるかに高速になる可能性はほとんどありません。.netのようなフレームワークが開発者に提供する生産性の向上により、通常のCでは数週間から数か月かかっていた作業を1日で行うことができます。開発者の給与に比べてハードウェアのコストが安いことと相まって、書く方がずっと安いです。高級言語で書かれたもので、どんな遅い時にもハードウェアを投げます。

JeffとJoelがCが「本物のプログラマ」言語であることを語る理由は、Cには手持ちがないためです。独自のメモリを割り当て、そのメモリの割り当てを解除し、独自の境界チェックなどを行う必要があります。そのようなことはありません。新しいobject();として ガベージコレクション、クラス、OOP、エンティティフレームワーク、LINQ、プロパティ、属性、フィールドなどはありません。ポインタ演算のようなことや、ポインタを逆参照する方法を知っている必要があります。そして、そのことについては、ポインタが何であるかを理解してください。スタックフレームとは何か、命令ポインタは何かを知る必要があります。作業しているCPUアーキテクチャのメモリモデルを知っている必要があります。マイクロコンピュータのアーキテクチャについては多くの暗黙の理解があります(通常、あなたが作業しているマイクロコンピュータ)Cでプログラミングするとき、C#やJavaなどでプログラミングするときは存在せず、必要もありません。これらの情報はすべて、コンパイラー(またはVM)プログラマーにオフロードされています。


「問題のハードウェアの増加」は、それが実際に可能な環境でのみ機能します。組み込み市場は完璧な反例です(そしてそれは巨大な市場です)。
ボブ・ソマーズ

ジェフとジョエルは、組み込みシステムではなくビジネスシステムについてのみブログを書いているので、それがこの質問が尋ねられたコンテキストであると想定するのは合理的です。
ロバートC.バース

1).netコードはCコードと同じ速さで実行されていますか?実際にCプログラムを書いたことがありますか?2)「問題が発生したときにハードウェアを追加する」という考え方が、私の1.3GHzデュアルコア2GBマシンがWindows XPにほとんど対応できず、800MHz 512MBマシンが最新バージョンのUbuntuで動作する理由です。
Robert Gamble、

はい、私はCを書きました。それは、人々がそうであるように気づくほどの栄光ではありません。そして、プロジェクトのコストが高すぎます。それは経済学の単純なケースです。Win2kをPentium Pro 180MHz、768MB RAMで何年もメールおよびWebサーバーとして実行しました。うまく動作しました。事例証拠は何も意味しません。
ロバートC.バース

Cは「派手」ではありませんが高速です。同じタスクを実行している間、Cはほとんど常にC#よりもはるかに高速であることを知るのに十分なCおよびC#コードを記述しました。一部のタスクでは、高水準言語よりも開発に時間がかかりますが、それはすべて、ジョブに適したツールを使用することであり、場合によってはCです。
Robert Gamble、

1

それは自動と手動の違いです。高レベルの言語は抽象化であり、したがって自動化されています。C / C ++は手動で制御および処理されます。エラーチェックコードでさえ手作業になる場合があります。

CとC ++もコンパイルされた言語です。つまり、ビジネスのあらゆる場所で実行されるものはありません。これらの言語は、作業するハードウェアに合わせて微調整する必要があるため、追加のレイヤーが追加されます。C / C ++コンパイラがすべてのプラットフォームでより一般的になっているので、これは今やややおかしくなっています。プラットフォーム間でクロスコンパイルを行うことができます。それはまだどこでも実行されているわけではありません。基本的にコンパイラAにコンパイラBに対して同じコードの異なるアーキテクチャでコンパイルするように指示します。

結論として、C言語は理解しやすくしたり、理由付けしたりすることはできません。これが、システム言語と呼ばれる理由でもあります。彼らはすべてのこの高レベルの抽象化ナンセンスの前に出てきました。これが、フロントエンドWebプログラミングに使用されない理由でもあります。彼らは単にタスクに適していません。従来の言語ツールでは解決できない複雑な問題を解決することを意味します。

これが、(マイクロアーキテクチャ、ドライバ、量子物理学、AAAゲーム、オペレーティングシステム)などのクレイジーなものを手に入れる理由です。スピードと数の処理が主な領域です。



1

次のような多くの理由があります。

  • アセンブリ言語にコンパイルされます。
  • 静的に型付けされています。
  • ガベージコレクションはありません。
  • エラー処理はありません。
  • 多くのプログラミング言語は新しい機能を追加します。Cの哲学の一部は、機能を追加するのではなく、物事をシンプルに保つことです。

オブジェクト指向ではないため、なぜ高速化する必要があるのですか?
sb27

A)オブジェクト指向プログラミングはガベージコレクションの必要性を生み出し、B)オブジェクト指向プログラミングのような大きな機能はコンパイラーに複雑さを追加します
Sapphire_Brick

A)いいえ。C ++またはRustを参照してください。B)はい。ただし、コンパイラーに新しい最適化の機会を与えます。
sb27

A)Rustにはコンパイル時のガベージコレクションがあり、c ++にはクラスのガベージコレクションがあります。そのため、デストラクタがあります。B)最適化された複雑さは依然として複雑です
Sapphire_Brick

A)ガベージコレクションではありません。プログラムをアセンブリで作成した場合でも、メモリ管理を行う必要があります。B)いいえ。より抽象化すると、オプティマイザはより適切な仮定を行うことができます。
sb27
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.