Cがとても危険なのに、なぜ人々はCを使うのですか?


132

Cの学習を検討しています。

しかし、なぜ「危険」に使用できるのにC(またはC ++)を使用するのでしょうか?

危険というのは、ポインターやその他の類似のものを意味します。

Stack Overflowの質問のように、gets関数は使用すべきでないほど危険なのはなぜですか?。プログラマーがJavaやPython、またはVisual Basicのような別のコンパイル言語を使用しないのはなぜですか?


152
シェフが「危険に」使用できるのに、なぜナイフを使用するのですか?
-oerkelens

78
偉大な力には大きな責任が伴います。
ピーターB

10
ジョー・ブロー、立派な?
マシュージェームスブリッグス

4
CがChoice Languageになった「Back In The Day」は、そのようなものを処理できることが期待されていたからです。当時のプロセッサは非常に低速だったため、解釈された言語またはバイトコード化された言語は遅すぎました。(今日はとローエンドのデスクトップPCを購入することができ2+ GHzのマルチコアCPUと4 GB $ 279のために、デルからのメモリを。あなたは、これは私のために4のような男にどのように表示されるか、絶対に信じられないほどのNO IDEA持たないMHzの PCを640 キロバイトのメモリで至福でした...)。それに直面する-ムーアの法則が勝った。ゲーム。 終わった!
ボブジャービス

6
@ボブ・ジャービス:ゲームオーバーではありません。2 + GHz、4GB PC、または最新のCUDA GPUを備えた数百台の4 GHz PCのクラスターなどが十分に高速だと思う場合は、単純に十分な問題に取り組んでいません:-)
jamesqf

回答:


246
  1. Cは、あなたが考えている他の多くの言語よりも前のものです。プログラミングを「安全」にする方法について私たちが今知っていることの多くは、Cのような言語の経験から来ています。

  2. C以来出てきたより安全な言語の多くは、目標を達成するためにより大きなランタイム、より複雑な機能セット、仮想マシンに依存しています。その結果、Cは、すべての一般的な/主流の言語の中で「最も低い共通分母」のようなもののままでした。

    • Cは比較的小さく、最も弱い環境でも適切に動作する可能性が高いため、実装がはるかに簡単な言語です。したがって、独自のコンパイラや他のツールを開発する必要がある多くの組み込みシステムは、機能的なコンパイラを提供できる可能性が高くなりますC用

    • Cは非常に小さくシンプルなので、他のプログラミング言語はCのようなAPIを使用して互いに通信する傾向があります。これはおそらく、私たちのほとんどがラッパーを介してのみ対話する場合でも、Cが真に死ぬことのない主な理由です。

  3. CおよびC ++を改善しようとする「より安全な」言語の多くは、プログラムのメモリ使用量と実行時の動作をほぼ完全に制御できる「システム言語」にはならない。最近、ますます多くのアプリケーションがそのレベルの制御を必要としないことは事実ですが、必要な場合は常に少数のケースが常に存在します(特に、これらすべてのためのこれらの素晴らしい、安全な言語を実装する仮想マシンとブラウザ内残りの皆んな)。

    現在、CやC ++よりも安全なシステムプログラミング言語(Rust、Nim、D、...)がいくつかあります。後知恵の利点があり、ほとんどの場合、このような細かな制御は必要ないため、本当に必要なときに切り替えることができるいくつかの安全でないフック/モード​​を備えた一般的に安全なインターフェイスを提供します。

  4. C内でも、実際に現れる潜行性のバグの数を大幅に減らす傾向がある多くのルールとガイドラインを学びました。一般に、これらのルールを遡及的に施行する標準を取得することは、既存のコードを大量に破壊するため不可能ですが、コンパイラ警告、リンター、その他の静的分析ツールを使用して、こうした簡単に予防可能な問題を検出するのが一般的です。これらのツールを飛ぶ色で渡すCプログラムのサブセットは、「単なるC」よりもはるかに安全であり、最近では有能なCプログラマーがそれらのいくつかを使用するようになります。


また、難読化されたJavaコンテストを難読化されたCコンテストのように楽しくすることはありません。


7
「最小公分母」は非難に聞こえます。私は、多くのはるかに重い言語とは異なり、Cはあなたが必要としない大量の余分な荷物を強制せず、必要なものを実装するための超高速の基盤を提供すると思います。それはあなたの意図ですか?
underscore_d

9
「あなたは本当に他の言語なしでは一方を持つことはできません。」:実際には多くの新しい言語(Rust、Nim、D、...)が試みます。これは基本的に、このレベルの制御が絶対に必要な場合に、言語の「安全な」サブセットと「安全でない」いくつかのプリミティブを一致させることになります。ただし、これらはすべてCとC ++から蓄積された知識に基づいているため、CとC ++が開発された時点では、どちらか一方がなくてはなりませんでした。 「安全でない」ビットですが、まだ追いついていません。
マチューM.

6
1)有効なポイントではありません!Cはこの意味で「安全な」言語であるAlgol 68から機能を取りました。著者はそのような言語を知っていました。他のポイントは素晴らしいです。
reinierpost

4
なつみ Microsoft Researchもご覧ください。特定の実際のワークロード向けの同等の非管理OSよりも速い(完全に偶然-これらの研究OSのほとんどの主な目標は安全性であり、速度である)ものを含め、過去10年または2年にわたっていくつかの管理OSを生産しました。速度の向上は主に安全性の制約によるものです。静的および動的な実行可能ファイルのチェックにより、アンマネージコードでは利用できない最適化が可能になります。見るべきことはかなりありますが、すべてが含まれており、情報源が含まれています;)
Luaan

3
@Luaan:みどりはすごいですね。ジョーのブログ記事をいつも楽しみにしています。
マチューM.

41

まず、Cはシステムプログラミング言語です。そのため、たとえば、Java仮想マシンまたはPythonインタープリターを作成する場合、それらを作成するにはシステムプログラミング言語が必要になります。

第二に、CはJavaやPythonのような言語にはないパフォーマンスを提供します。通常、JavaおよびPythonでの高性能コンピューティングは、Cなどの高性能言語で記述されたライブラリを使用して、面倒な作業を行います。

第三に、CはJavaやPythonのような言語よりもフットプリントがはるかに小さくなります。これにより、組み込みシステムで使用できるようになります。組み込みシステムは、JavaやPythonなどの言語の大規模なランタイム環境とメモリ要求をサポートするために必要なリソースを持たない場合があります。


「システムプログラミング言語」とは、強力なシステムを構築するのに適した言語です。現状では、JavaとPythonはシステムプログラミング言語ではありません。「システムプログラミング言語を作成する正確な理由」はこの質問の範囲外ですが、システムプログラミング言語は、基盤となるプラットフォームでの作業をサポートする必要があります。

一方(コメントへの応答で)、システムプログラミング言語は自己ホストである必要ありませ。この問題は、元の質問が「なぜCを使用するのか」と尋ね、最初のコメントがPyPyを持っているときに「なぜCのような言語が必要なのか」と尋ねたためです。PyPy 実際にCを使用します。はもともと質問に関連していましたが、残念ながら(そして紛らわしいことに)「セルフホスティング」は実際にはこの答えに関連していません。ごめんなさい

要約すると、JavaとPythonはシステムプログラミングに適していません。主な実装が解釈されるため、またはネイティブにコンパイルされた実装が自己ホストされないためではなく、基盤となるプラットフォームでの作業に必要なサポートを提供しないためです。


19
「Java仮想マシンまたはPythonインタープリターを作成する場合、それらを作成するにはシステムプログラミング言語が必要になります。」あれ?PyPyをどのように説明しますか?コンパイラー、インタープリター、または仮想マシンを作成するためにCのような言語が必要なのはなぜですか?
ビンセントサバード

10
「Java仮想マシンまたはPythonインタープリターを作成する場合は、システムプログラミング言語が必要です」と言ったときに、Java仮想マシンまたはPythonインタープリターを作成するにはシステムプログラミング言語が必要だと主張したと思います。PyPyで満足できない場合は、Haskellで書かれたインタープリターまたはコンパイラーを調べることもできます。または、本当に、あなたの主張をサポートする参照を追加してください。
ビンセントサバード

16
たとえそれが一番下のカメであっても、PyPyのようなものは、他の言語で書かれたPythonインタープリターなしでは存在できません。
Blrfl

18
@Birflしかし、それはあまり多くを語っていません。Cはアセンブリコンパイラなしでは作成できませんでした。また、Cを実装するハードウェアなしではアセンブリを作成できません。
ガーデンヘッド

11
Cコンパイラがどこかに関与しているためにPyPyが「システムプログラミング言語」ではない場合、アセンブラがどこかで使用されているため、Cもシステムプログラミング言語ではありません。実際、最近はCを他の言語に翻訳するのが一般的ではないでしょうか?例:LLVM

30

さらに別の回答を追加して申し訳ありませんが、既存の回答のいずれかがあなたの最初の文を直接記述しているとは思わない:

「Cの学習を検討しています」

どうして?現在Cが通常使用している種類の処理(デバイスドライバー、VM、ゲームエンジン、メディアライブラリ、組み込みシステム、OSカーネルなど)を行いたいですか?

もしそうなら、そうです、あなたが興味のある人に応じてCまたはC ++を学んでください。あなたの高水準言語が何をしているのかをより深く理解できるように学びたいですか?

次に、安全性の懸念に言及します。後者を実行するために安全なCを深く理解する必要は必ずしもありません。同じように、高水準言語のコード例では、本番の準備ができていなくても要点がわかります。

要点をつかむために、Cコードをいくつか書いてください。次に、棚に戻します。プロダクション Cコードを書きたくない限り、安全性についてあまり心配しないでください。


2
本当の質問と思われるものに答える素晴らしい仕事です!C / C ++および「より安全な」言語を本当に評価するための素晴らしい方法は、単純なデータベースエンジンのようなものを書くことです。あなたが試みるそれぞれのアプローチについて良い感触を得て、それがあなたをどこへ導くのかを見るでしょう。どちらでも自然に感じるものが表示され、自然なアプローチが失敗する場所がわかります(たとえば、Cで生データを「シリアル化」するのは非常に簡単です-データを書き込むだけです!;結果は移植性がないため、限定的に使用される場合があります)。ほとんどの問題は発生しにくいため、安全性を理解することは困難です。
ルアーン

1
@Luaan、正確に、ポインターを使用して文字列をコピーする方法を学ぶことはあなたにアイデアを与えます。
ジャレッド・スミス

2
これは本当に問題ではありませんでした。しかし、それは論争をするのに役立ちました。私はそれをすることにしました。私は、すべてが築かれている内面的な働きについてもっと知りたいと思っています。そして、私はプログラミングが好きです。このようにして、コンピューターの内部の仕組みをより良く理解したいと思っています。それはただの楽しみのためです。
トリスタン

10
私は最後の文に同意しません。悪い習慣を身につける前に、どうやってそれを行うのかを学びましょう。
-glglgl

2
@glglgl IDK、ウェブ上でJavaScriptスニペットを読んだ(または書いた)場合、プロダクションの準備ができていないことを理解してそうします。例外処理はありません。その点を理解するために必要です。それはすべて生産コードに必要です。なぜこれが違うのですか?私は自分の啓発のために素朴なCを書くことができますが、それをそこに置きたいならもっと多くの仕事をする必要があると知的に理解しています。
ジャレッド・スミス

14

これは膨大な回答を伴う巨大な質問ですが、短いバージョンでは、各プログラミング言語は異なる状況に特化しています。たとえば、Web用のJavaScript、低レベルのもの用のC、Windows用のC#などです。プログラミングを知ったら、何をしたいかを知っておくと、どのプログラミング言語を選択するかがわかります。

最後のポイントであるJava / Pythonを介したC / C ++を使用する理由は、多くの場合、速度が低下します。私はゲームを作っていますが、Java / C#はゲームを実行するのに十分な速度に近づいています。結局、ゲームを1秒あたり60フレームで実行し、ゲームで多くのことをしたい場合(レンダリングは特に高価です)、可能な限り高速に実行するコードが必要です。Python / Java / C#/その他の多くは、「インタープリター」で実行されます。これは、メモリやガベージコレクションの管理など、C / C ++ではできない退屈なものをすべて処理するソフトウェアの追加レイヤーです。この余分なオーバーヘッドにより速度が低下するため、表示されるほとんどすべての大規模なゲームは(過去10年間に)CまたはC ++で実行されました。例外があります。UnityゲームエンジンはC#*を使用し、MinecraftはJavaを使用しますが、それらは例外であり、ルールではありません。一般に、

* UnityでさえすべてC#ではなく、その大部分はC ++であり、ゲームコードにはC#を使用します。

編集 これを投稿した後に表示されたコメントのいくつかに応答するために:多分私はあまりにも単純化しすぎていたので、私は単に全体像を示していました。プログラミングでは、答えは決して簡単ではありません。C用のインタープリターがあり、Javascriptはブラウザーの外部で実行でき、C#はMonoのおかげでほぼ何でも実行できます。異なるプログラミング言語は異なるドメインに特化していますが、どこかのプログラマーが、どの言語をどのコンテキストでも実行する方法を見つけたのでしょう。OPはあまりプログラミングを知らないように見えたので(私の側の仮定、間違っていればごめんなさい)、私は答えをシンプルにしようとしていました。

C#がC ++とほぼ同じ速さであるというコメントについては、そこにキーワードがあります。私が大学にいたとき、私たちは多くのゲーム会社を視察し、私の先生(私たちはC#からC ++に一年中移行することを勧めてきました)がすべての会社のプログラマーに尋ねました。 C#が遅すぎると言いました。一般に、高速で実行されますが、実行時に制御できないため、ガベージコレクターはパフォーマンスを損なう可能性があります。また、推奨されたときに実行しない場合は無視する権利があります。高性能にするために何かが必要な場合、それほど予測できないものは必要ありません。

「速度にちょうど達する」というコメントに対応するために、C#の速度向上の多くはハードウェアの向上によるものですが、.NETフレームワークとC#コンパイラが改善されるにつれて、いくつかの速度が向上しました。

「ゲームはエンジンと同じ言語で書かれている」コメントについては、それは異なります。一部はそうですが、多くは言語のハイブリッドで書かれています。UnrealはUnrealScriptとC ++を実行でき、UnityはC#JavascriptとBooを実行します。CまたはC ++で記述された他の多くのエンジンはPythonまたはLuaをスクリプト言語として使用します。簡単な答えはありません。

また、「200fpsまたは120fpsでゲームを実行する場合は誰が気にするか」を読むように迷惑をかけたため、ゲームが60fpsよりも高速で実行されている場合、平均モニターでも更新されないため、おそらくCPU時間を無駄にしています速い。いくつかのハイエンドと新しいものはありますが、標準ではありません(まだ...)。

そして、「数十年にわたる技術の無視」の発言について、私はまだ20代前半にいるので、後方に外挿するとき、私は主に年長で経験豊富なプログラマーが私に言ったことを反映しています。明らかにこのようなサイトで争われますが、検討する価値があります。


4
C#for Windows for Windows」-ああ、それはそのような誤fallです。また、例を提供します。団結。私の知る限り、C#APIを提供するように書かれているわけではありません。なぜなら、言語は素晴らしく適応性があるからです。本当にうまく設計されています。そして、私はc ++の方が好きですが、当然のことながらクレジットを与えるべきです。たぶん、C#と.NETを混ぜたのでしょうか?彼らは頻繁に一緒に出かけます。
luk32

2
「UnityでさえすべてがC#であるとは限らず、その巨大な塊はC ++です」そして?UnityのゲームはC#を頻繁に使用することが多く、かなり前から存在しています。C#が「ごく最近速度に達している」ことを示唆するには、より多くのコンテキストを必要とするか、この数十年の技術に盲目になるリスクがあります。
NPSF3000

2
ほとんどすべての大規模なゲームは、使用するエンジンの言語で記述されていました。複製が必要な作業量が非常に多かったため、他の技術的な考慮は考慮に値しませんでした。レンダリングは確かに高価ですが、今日ではそれはすべてシェーダーで書かれており、ロジックループの言語は無関係です。
ピーターテイラー

2
C#は常にJITコンパイルされており(Javaのコメントが正しい場合とは異なり)、何をしているのかがわかっていれば、get goからC ++に非常に近い実行速度が可能です。それは2003年です-私が最近検討するものではありません。生の速度はゲームの主な問題ではありません(特にGPUでプログラム可能なシェーダーを使用する場合)。C#などの言語を多かれ少なかれ人気にしているものもあります。2つの主な問題は、API(C指向が非常に多く、インターフェイスに費用がかかる可能性があります)とGC(主に生のスループットではなくレイテンシの問題)です。
ルアーン

1
@gbjbaanb CPUが高速であるだけではありません-大部分は、C ++とCがコンパイラとランタイムを完璧にするのに何十年もかかっていたのに対し、Javaは基本的にゼロから始まりました(主にマルチプラットフォームプラットフォームとして設計されている)。VMが改善されると(たとえば、インタプリタからJITコンパイラへの切り替え、GCが改善されるなど...)、Javaアプリケーションのパフォーマンスも改善されました。C / C ++がまだ持っているエッジの多くは、「何も壊れないことを望みます」アプローチにあります-「不要」と見なされる多くのチェックを回避します。しかし、それはまだ巨大なメモリの
浪費です。

13

「ポインタを持っている」ためにCが安全でないと主張するのは面白いです。逆のことが言えます。JavaとC#には、実際にはポインターしかありません(非ネイティブ型の場合)。Javaで最も一般的なエラーは、おそらくNullポインター例外です(https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoareを参照)。2番目の最も一般的なエラーは、おそらく未使用のオブジェクトへの隠された参照を保持することです(たとえば、閉じられたダイアログは破棄されません)。

C#とJavaをより安全にする2つの基本的なメカニズムがあり、2つの異なる方法でより安全です。

  • ガベージコレクションにより、プログラムが破棄されたオブジェクトにアクセスしようとする可能性が低くなります。これにより、プログラムが予期せず終了する可能性が低くなります。Cとは対照的に、JavaおよびC#はデフォルトで非ネイティブデータを動的に割り当てます。これにより、プログラムロジックは実際にはより複雑になりますが、組み込みのガベージコレクションが(犠牲を払って)難しい部分を引き継ぎます。

最近のC ++のスマートポインターは、プログラマーにとってその仕事を簡単にします。

  • JavaとC#は、精巧なランタイムによって解釈/実行される中間コードにコンパイルされます。ランタイムはプログラムの不正なアクティビティを検出できるため、これによりセキュリティレベルが追加されます。プログラムが安全にコーディングされていない場合でも(両方の言語で可能)、理論上はそれぞれのランタイムがシステムへの「ブレークアウト」を防ぎます。
    ランタイムは、試行されたバッファオーバーランなどから保護しませんが、理論的にはそのようなプログラムの悪用を許可しません。対照的に、CおよびC ++では、プログラマはエクスプロイトを防ぐために安全にコーディングする必要があります。通常、これはすぐには達成されませんが、レビューと反復が必要です。

ただし、複雑な実行時間はセキュリティ上のリスクでもあることに注意してください。安全性の問題が新たに発見されたため、Oracleは2週間ごとにJVMを更新しているようです。もちろん、JVMを検証することは、単一のプログラムよりもはるかに困難です。

したがって、複雑な実行時の安全性はあいまいであり、ある程度欺くことができます。平均的なCプログラムは、レビューと反復により、合理的に安全にすることができます。平均的なJavaプログラムは、JVMと同じくらい安全です。つまり、そうではありません。決して。

gets()あなたがリンクしていることに関する記事は、コア言語ではなく、今日異なって行われる歴史的なライブラリの決定を反映しています。


3
オリジナルの著者のポイントは、Cではこれらのポインターに対して未チェックのアクションを実行できることです。Javaでは、すぐに素敵な例外が発生します。Cでは、アプリケーションの状態が破損するまで、無効な場所を読んでいることに気付かない場合があります。
サムデュフェル

1
また、stackoverflow.com / questions / 57483 /…-javaには「実質的に参照のみ」があると言う方が正確です。
サムデュフェル

4
明示的なポインターを回避しようとすると、あらゆる種類の興味深いバグが発生します。通常、基本的な問題はコピーと参照の混乱です。Cでは、何かへのポインタを渡した場合、それを変更すると元に影響することがわかります。ポインターを回避しようとする試みのいくつかは、この区別を曖昧にし、深いコピーの迷路、浅いコピー、および一般的な混乱をもたらします。
アーリースティーブンス

OracleのJVMが(悪用可能なセキュリティ脆弱性の出血の観点から)ひどく、したがってマネージド言語のランタイムがマネージド言語を使用するよりも多くのセキュリティ上の懸念をもたらすと断言することは、Adobe Flashが不安とプログラムのソースとして恐ろしいと言うようなものですWebサイトからのビデオとアニメーションの再生は本質的にばかげて安全である必要がありますか。すべてのJavaランタイムがOracle / Sunの1990年代のJVMの憎悪と同じくらい悪いわけではなく、すべての管理言語がJavaであるわけではありません。(まあ、明らかに。)
主に

@halfinformed Well; 私は、プログラムはそのランタイムと同じくらい安全であり、「あなたの平均」(読み:小さいっぽい)プログラムは、バイトコードインタプリタのような大きなランタイムよりも安全にできると言っていました。その声明は否定できないようです。特定のスタンドアロンプ​​ログラムまたは特定のランタイムが他よりも安全であるかどうかは、それぞれの複雑さと設計、コーディング、保守の品質に依存します。たとえば、sendmailがOracleのJava VMよりも安全であるとは言いません。しかし、qmailはそうかもしれません。
ピーターA.シュナイダー

10

「安全」には速度がかかるため、「安全」な言語はより遅い速度で動作します。

CやC ++などの「危険な」言語を使用する理由を尋ね、誰かにPythonやJavaなどでビデオドライバーなどを書いてもらい、「安全」についてどのように感じているかを確認してください:)

しかし、真剣に、ピクセル、レジスタなどを操作できるようにするには、マシンのコアメモリにできるだけ近づける必要があります。JavaまたはPythonは、パフォーマンスに値する速度でこれを行うことはできません... CとC ++の両方ポインタなどを使用してこれを行うことができます...


20
一般に、安全性がスピードを犠牲にすることは真実ではありません。最も安全な利用可能な言語は、コンパイル時にほとんどのチェックを行います。O'Caml、Ada、Haskell、Rustはすべて、平均実行速度の点でCに大きく遅れをとっていません。彼ら通常行うことは、プログラムサイズ、メモリ効率、レイテンシ、そして明らかにコンパイル時間の大きなオーバーヘッドです。そして、はい、彼らは金属に近いものに問題を抱えています。しかし、それは実際には速度の問題ではありません。
左回り約

6
また、Cはあなたが思っていることをしません。C は抽象マシンです。何にも直接アクセスすることはできません-それは良いことです。Cがどれだけ隠れているかを見るために、最新のアセンブリを見ることもできません。最新のアセンブリ(例:TASM)は、Cが開発された当時の高水準言語と見なされていました。誰かが「安全な」言語でドライバーを書いてくれたらとてもうれしいです-セキュリティホールは言うまでもなく、これらのBSODやフリーズを避けるのに非常に役立ちます:)そして最も重要なことは、より安全なシステム言語がありますC.より
-Luaan

3
@Wintermute安全機能が必然的に速度を低下させる方法についてコメントする前に、Rustを実際に調べたいと思います。地獄、Cの低レベルの型システムは、実際にコンパイラーが行うことができる多くの非常に有用な最適化を禁止します(特に、大規模なcプロジェクトがどこかで厳密なエイリアスに違反しないように管理できないことを考慮した場合)。
Voo

7
@Wintermuteうんあなたは、パフォーマンスのオーバーヘッドを導入することなく、任意のより安全なC ++ / Cを作ることができない神話は私が取る理由である非常に持続的である。この(があるという深刻ないくつかの、これは確かに真実[境界チェック]である領域が)。さて、なぜRustはそれほど普及していないのですか?歴史と複雑さ。Rustはまだ比較的新しく、Cで書かれた最大のシステムの多くはRustが発明される前から存在していました。もっと安全であったとしても、新しい言語で100万LOCを書き換えるつもりはありません。また、すべてのプログラマーとその犬はC、Rustを知っていますか?たくさんの人を見つけてください。
Voo

3
@Voo DogsはCをやっていますか?...私はそこにたくさんの悪いコードを見たのも不思議ではありません... j / k Rustについてのポイント(私はそれをダウンロードしてインストールしたので、追加する別の変換があるかもしれません) Rustを正しく実行するために...「D」にも同じ拡張を作成できました:)
Wintermut3

9

上記以外にも、かなり一般的な使用例が1つあります。これは、Cを他の言語の共通ライブラリとして使用している場合です。

基本的に、ほぼすべての言語にはCへのAPIインターフェイスがあります。

簡単な例では、Linux / IOS / Android / Windows用の一般的なアプリケーションを作成してみてください。そこにあるすべてのツールに加えて、Cでコアライブラリを作成し、各環境のGUIを変更しました。つまり、

  • IOS:ObjectiveCはCライブラリをネイティブに使用できます
  • Android:Java + JNI
  • Linux / Windows / MacOS:GTK / .Netを使用すると、ネイティブライブラリを使用できます。Python、Perl、Rubyを使用する場合、それぞれにネイティブAPIインターフェイスがあります。(JavaとJNI)。

私の2セント、


PHPを使用するのが好きな理由の1つは、そのライブラリのほとんどすべてが実際にCで書かれているためです-ありがたいことに、PHPは耐えられないほど遅いでしょう:) PHPは、 「危険」なことは何でもします(だからこそ、私は他の何よりも多くのPHPコードを書く傾向があります-私ずさんなコードが好きです!:D)それにこれとは対照的に、いくつかのパフォーマンスの向上を;-)与えるためにCライブラリは、Cでずさんなコードを書くことは、大きなノーノー...である
グウィネスLlewelyn

7

Cの根本的な難点は、名前が同じ構文であるが非常に異なるセマンティクスを持つ多くの方言を記述するために使用されることです。一部の方言は他の方言よりもはるかに安全です。

デニスリッチーが最初に設計したCでは、Cステートメントは通常、予測可能な方法でマシン命令にマップされます。Cは符号付き算術オーバーフローのようなものが発生したときに異なる動作をするプロセッサで実行できるため、算術オーバーフローの場合のマシンの動作を知らないプログラマーは、そのマシンで実行されているCコードがどのように動作するかを知りませんが、マシンが特定の方法で動作することがわかっている場合(サイレント2の補数ラップアラウンドなど)、そのマシンでの実装は通常同様に実行されます。Cが高速であるという評判を得た理由の1つは、エッジケースシナリオでのプラットフォームの自然な動作がニーズに合うことをプログラマーが知っている場合、そのようなシナリオを生成するコードをプログラマーまたはコンパイラーが記述する必要がないことでした。

残念なことに、コンパイラの作者は、標準ではそのような場合に実装が行う必要のある要件を課していないため(予想どおりに動作しない可能性のあるハードウェア実装を可能にするためのゆるみ)、コンパイラは法律を無効にするコードを自由に生成する必要があると考えています時間と因果関係。

次のようなものを検討してください。

int hey(int x)
{
   printf("%d", x);
   return x*10000;
}
void wow(int x)
{
  if (x < 1000000)
    printf("QUACK!");
  hey(x);    
}

ハイパーモダン(しかし流行の)コンパイラ理論は、コンパイラが「QUACK!」を出力することを示唆しています。条件が偽の場合、プログラムは結果を無視する乗算を実行する未定義の動作を呼び出すことになってしまうため、無条件に。規格では、コンパイラはそのような場合に好きなことを行うことができるため、コンパイラは「QUACK!」を出力できます。

Cは以前はアセンブリ言語より安全でしたが、ハイパーモダンコンパイラを使用する場合はその逆です。アセンブリ言語では、整数オーバーフローにより計算が無意味な結果をもたらす場合がありますが、ほとんどのプラットフォームではその効果の範囲になります。とにかく結果が無視されることになっても、オーバーフローは問題になりません。ただし、ハイパーモダンCでは、通常「無害」な未定義動作の形式(計算での整数オーバーフローなどが無視される)でさえ、任意のプログラム実行を引き起こす可能性があります。


1
ハイパーモダンコンパイラでも、Cは配列の境界チェックを行いません。もしそうなら、それは言語の定義と互換性がありません。私はその事実を時々使用して、負のインデックスを持つために、配列の中央に追加のポインターを持つ配列を作成します。
ロバートブリストージョンソン

1
「QUACK!」を生成するあなたの例の証拠を見てみたいです。無条件。xは確かに比較の時点で1000000より大きくなる可能性があり、オーバーフローを引き起こす後の評価はそれを妨げません。さらに、オーバーフローが発生した乗算を削除できるインライン化を有効にしている場合、暗黙的な範囲制限に関する議論は成り立ちません。
グラハム

2
@ robertbristow-johnson:実際、規格では、たとえばint arr[5][[5]、アクセスarr[0][5]を試みると未定義の動作が発生することを明確に述べています。このような規則により、コンパイラは、の値に関係なく、4に等しいとarr[1][0]=3; arr[0][i]=6; arr[1][0]++;推論するようなものを与えられarr[1][0]ますi
-supercat

2
@ robertbristow-johnson:コンパイラーが構造体内の配列をギャップなしで連続して割り当てたとしても、配列の1つのインデックス付けが別の配列に影響を与えることを保証しません。gccがそのようなコードを処理する方法の例については、godbolt.org / g / Avt3KWを参照してください。
-supercat

1
@ robertbristow-johnson:アセンブリにコメントして、何をしているのか説明しました。コンパイラは、コードが1をs-> arr2 [0]に格納してからs-> arr2 [0]をインクリメントすることを確認します。そのため、gccは、コードが値value 2 to s-> arr1 [i]は、s-> arr1 [0]の値に影響を与える可能性があります(標準に従ってできないため)。
-supercat

5

歴史的な理由。新しいコードを書くことはあまりありませんが、ほとんどの場合、何十年も実行されてきた古いものを維持および拡張することができます。FortranではなくCであることに満足しています。

一部の学生が「YをやれるのになぜこのひどいXをやるのか」と言うとイライラすることがあります。まあ、Xは私が持っている仕事であり、非常にうまく支払います。私は時々Yをやったことがあり、それは楽しかったですが、Xは私たちのほとんどがすることです。


5

「危険」とは何ですか?

Cが「危険」であるという主張は、言語の火炎戦争(Javaと比較して最も頻繁に)で頻繁に話題になっています。ただし、この主張の証拠は不明です。

Cは、特定の機能セットを持つ言語です。これらの機能の一部は、他の種類の言語では許可されない特定の種類のエラーを許可する場合があります(Cのメモリ管理のリスクは通常強調表示されます)。ただし、これはCが全体的に他の言語よりも危険であるという議論と同じではありません。この点に関して説得力のある証拠を提供している人は誰もいません。

また、「危険」はコンテキストに依存します。何をしようとしているか、どのようなリスクを心配していますか?

多くの状況で、私はCを高レベル言語よりも「危険」だと考えています。なぜなら、基本的な機能を手動でより多く実装する必要があり、バグのリスクが高まるからです。たとえば、Cで基本的なテキスト処理やWebサイトの開発を行うのは、他の言語にはこれを非常に簡単にする機能があるため、通常は馬鹿げています。

ただし、CおよびC ++はミッションクリティカルなシステムで広く使用されています。これは、ハードワードをより直接制御できる小さな言語がそのコンテキストで「安全」であると見なされるためです。非常に良いスタックオーバーフローの答え

CおよびC ++はこのタイプのアプリケーション用に特別に設計されたものではありませんが、いくつかの理由により、組み込みおよび安全性が重要なソフトウェアに広く使用されています。注目すべき主な特性は、メモリ管理(ガベージコレクションなどを回避できるようにする)、シンプルで適切にデバッグされたコアランタイムライブラリ、および成熟したツールサポートです。今日使用されている多くの組み込み開発ツールチェーンは、1980年代および1990年代に最初に開発されたものであり、現在の技術であり、当時流行していたUnix文化に由来しているため、これらのツールはこの種の作業で人気があります。

手動のメモリ管理コードはエラーを回避するために慎重にチェックする必要がありますが、ガベージコレクションに依存する言語では利用できないアプリケーションの応答時間をある程度制御できます。CおよびC ++言語のコアランタイムライブラリは比較的単純で、成熟しており、十分に理解されているため、利用可能な最も安定したプラットフォームの1つです。


2
ハイパーモダンCは、アセンブリ言語や、自然なマシンコード操作が行われるエッジケースに関係なく、一貫してC操作をマシンコード操作に変換するかのように一貫して動作するCの真の低レベル方言よりも危険だと思います動作を定義しましたが、C標準は要件を課しません。整数オーバーフローが時間のルールと因果関係を無効にする可能性があるハイパーモダンなアプローチは、安全なコードの生成にあまり適していないようです。
-supercat

5

既存の回答に追加するために、比較的安全であるため、プロジェクトにPythonまたはPHPを選択するということは、すべて良いことです。しかし、誰かがそれらの言語を実装する必要があり、実装する場合、おそらくCで実装するでしょう(または、まあ、それと似たようなものです)。

だから、人々はC を使用するのです— あなたが使いたいと思う危険度の低いツールを作成するために。


2

あなたの質問を言い換えさせてください:

[ツール]の学習を検討しています。

しかし、[危険]に使用できるのに、なぜ[ツール](または[関連ツール])を使用するのでしょうか?

プログラミング言語を含む、あらゆる興味深いツールを危険にさらすことができます。あなたは学ぶあなたができるので、より多く行う(このツールを使用する際にあまり危険が作成されていることなど)以上。特に、ツールを学習して、そのツールが適していることを実行できるようにします(そして、おそらく、そのツールが知っているツールの中で最高のツールであるときを認識します)。

たとえば、直径6 mm、深さ5 cmの円柱状の穴を木のブロックに配置する必要がある場合、ドリルはLALRパーサーよりもはるかに優れたツールです。これら2つのツールが何であるかを知っていれば、どちらが正しいツールであるかがわかります。ドリルの使い方を知っているなら、出来上がり!

Cは単なるツールです。他のタスクよりも一部のタスクの方が優れています。ここでの他の答えはこれに対処します。Cを学べば、いつそれが適切なツールであり、そうでないかを認識するようになります。


このような答えが、質問が「主に意見に基づいた」ものとして捨てられる理由です。Cに利点があると言ってはいけません、彼らが何であるかを言ってください!
reinierpost

1

Cの学習を検討しています

Cを学習しない特別な理由はありませんが、C ++をお勧めします。Cが行うことの多くを提供し(C ++はCのスーパーセットであるため)、大量の「エクストラ」を備えています。C ++より前にCを学習する必要はありません。これらは事実上別個の言語です。

別の言い方をすれば、Cが木工ツールのセットである場合、おそらく次のようになります。

  • ハンマー
  • 手のこぎり
  • ハンドドリル
  • ブロックサンダー
  • のみ(たぶん)

これらのツールを使用して何でも作成できますが、素晴らしいものは多くの時間とスキルを必要とする可能性があります。

C ++は、お近くのハードウェアストアにある電動工具のコレクションです。

基本的な言語機能を使用して開始する場合、C ++には追加の学習曲線がほとんどありません。

しかし、なぜ「危険」に使用できるのにC(またはC ++)を使用するのでしょうか?

何人かの人々はイケアの家具を望まないからです。=)

真面目な話ですが、CやC ++よりも「高い」言語の多くは、特定の側面で(潜在的に)「使いやすく」するものがあるかもしれませんが、これは必ずしも良いことではありません。何かが行われたり、機能が提供されなかったりする方法が気に入らない場合、おそらくそれについてできることはあまりありません。一方、CとC ++は十分な「低レベル」言語機能(ポインターを含む)を提供するため、多くのものに直接(特にハードウェアまたはOSごとに)アクセスしたり、自分でビルドしたりできます。実装されている言語。

具体的には、Cには次の一連の機能があり、多くのプログラマにとって望ましいものとなっています。

  • 速度 -比較的単純で、長年にわたってコンパイラーが最適化されているため、ネイティブで非常に高速です。また、多くの人々は、言語を使用するときに特定の目標への多くのショートカットを見つけました。
  • サイズ -速度のリストにあるものと同様の理由で、Cプログラムを非常に小さくすることができ(実行可能サイズとメモリ使用量の両方の面で)、メモリが限られた環境(組み込みまたはモバイル)で望ましい。
  • 互換性 -Cは古くから存在し、誰もがツールとライブラリを持っています。言語自体も気難しいものではありません-プロセッサが命令を実行し、メモリが内容を保持することを期待しています。

    さらに、Application Binary Interface(ABI)と呼ばれるものがあります。つまり、プログラムがマシンコードレベルで通信する方法であり、アプリケーションプログラミングインターフェイス(API)よりも優れている場合があります。C ++などの他の言語はABIを持つことができますが、通常、これらはCのものよりも統一されていない(同意している)ため、何らかの理由でABIを使用して別のプログラムと通信する場合、Cは優れた基礎言語になります。

プログラマーがJavaやPython、またはVisual Basicなどの別のコンパイル言語を使用しないのはなぜですか?

効率性(および場合によっては、メモリに比較的直接アクセスしないと実装できないメモリ管理スキーム)。

ポインターを使用してメモリに直接アクセスすると、メモリのキュービホールの小さなものとゼロに汚れた足を直接置くことができ、その平均的な先生がおもちゃを配るのを待つ必要がない場合、多くのきちんとした(通常は迅速な)トリックが導入されますプレイタイムでそれらを再びすくい上げます。

要するに、ものを追加するとラグが発生する可能性があり、そうでない場合は不要な複雑さが生じます。

スクリプト言語とその同類に関して、二次プログラムを必要とする言語がC(またはコンパイルされた言語)がネイティブに実行するのと同じくらい効率的に実行するように努力する必要があります。オンザフライインタプリタを追加すると、別のプログラムをミックスに追加するため、実行速度が低下し、メモリ使用量が増加する可能性が本質的に導入されます。プログラムの効率は、元のプログラムコードをどの程度(貧弱=))作成したかと同じくらい、この2次プログラムの効率に依存しています。言うまでもなく、プログラムは、実行するために2番目のプログラムに完全に依存しています。その2番目のプログラムは、特定のシステムに何らかの理由で存在しませんか?コードはありません。

実際、「余分な」何かを導入すると、コードが遅くなるか複雑になる可能性があります。「恐ろしいポインタのない」言語では、あなたの後ろで他のコードがクリーンアップされるか、そうでなければ「安全な」方法を見つけ出すのを常に待っています-あなたのプログラムはまだと同じメモリアクセス操作をしているからですポインター。あなたはそれを処理しているだけではありません(そのため、f * ckできません、天才= P)。

危険というのは、ポインターやその他の類似のものを意味します。[...] Stack Overflowの質問のように、gets関数は使用すべきではないほど危険なのはなぜですか?

受け入れられた答えごと:

「1999 ISO C規格までは言語の公式部分でしたが、2011規格によって公式に削除されました。ほとんどのC実装は引き続きサポートしていますが、少なくともgccはそれを使用するコードに対して警告を発行します。」

何かを言語で行うことができるので、やらなければならないという考えはばかげています。言語には修正される欠陥があります。古いコードとの互換性の理由から、この構成は引き続き使用できます。しかし、プログラマーにgets()の使用を(おそらく)強制することはなく、実際、このコマンドは本質的に安全な代替手段に置き換えられました。

さらに重要なのは、gets()の問題自体はポインターの問題ではありません。これは、メモリの安全な使用方法が必ずしもわからないコマンドの問題です。抽象的な意味では、これはすべてのポインターの問題です-想定外のことを読み書きします。これはポインターの問題ではありません。ポインターの実装に問題があります。

明確にするために、ポインタは、意図しないメモリロケーションに誤ってアクセスするまで危険ではありません。そして、それでもコンピューターが溶けたり爆発したりすることを保証するものではありません。ほとんどの場合、プログラムは機能しなくなります(正しく)。

ただし、ポインターはメモリの場所へのアクセスを提供し、データと実行可能コードがメモリ内に一緒に存在するため、メモリを正しく管理したい偶発的な破損の本当の危険が十分にあります。

その点まで、真に直接的なメモリアクセス操作は何年も前に比べて一般にあまり利益をもたらさないことが多いため、C ++などの非ガベージコレクション言語でも、メモリの効率と安全性のギャップを埋めるスマートポインタなどを導入しています。

要約すると、ポインターが安全に使用されている限り、ポインターを恐れる理由はほとんどありません。サウスパーク版のスティーブ「クロコダイルハンター」アーウィンのヒントを参考にしてくださいクロックスの尻穴に親指を刺さないでください


2
Cの代わりにC ++を学ぶという提案には同意しません。良いC ++を書くことは良いCを書くよりも難しく、C ++を読むことはCを読むよりもはるかに難しいです。したがって、C ++の学習曲線は非常に急です。「C ++はCのスーパーセットです」これは、ブーツがスリッパのスーパーセットであると言っているようなものです。それらには異なる利点と使用方法があり、それぞれには他の機能にはない機能があります。
-martinkunev

「良いC ++を書くことは、良いCを書くよりも難しい」-もちろん。=) "[R] C ++を読むことはCを読むことよりはるかに難しい"-高度なプログラミングは魔法と見分けがつかない可能性が高い;-)私の2セントは、これは言語依存よりもプログラマ依存であるということです。このカテゴリ。「つまり、C ++の学習曲線は非常に急です。」-長い目で見れば、はい。短期的にはそうではありません(私の意見)。逸話的に、CおよびC ++のほとんどの基本的な言語コースは、C ++のクラスを除いて、ほぼ同じ一般的な種類の教材をカバーする可能性があります。
アナクスナマン

2
「それらには異なる利点と使用法があり、それぞれに他の機能にはない機能があります。」-「C [。]を学ばない特別な理由はない」と述べたように、Cは素晴らしい言語であり、私はそれを守ります。OPや他の人に適している場合は、学習を完全にサポートします。=)
アナクスナマン

Learning Cは、機械がどのように機能するかを説明します(完全にダウンしているわけではありませんが、金属に一歩近づいています)。それはそれを学ぶための非常に良い理由です。
Agent_L

1

いつものように、プログラミング言語は問題解決の結果にすぎません。実際には、Cだけでなく、さまざまな言語(およびコンピューターをプログラミングする他の方法、GUIツールまたはコマンドインタープリター)を学習して、問題を解決する際に使用する適切なツールボックスを用意する必要があります。

問題がJavaのデフォルトライブラリに含まれているものに役立つ場合があります。そのような場合は、Javaを選択してそれを活用できます。それ以外の場合は、Windowsで.NETランタイムをはるかに単純化する必要があるため、C#またはVBを使用できます。問題を解決するグラフィカルツールまたはコマンドスクリプトがある場合は、これらを使用できます。複数のプラットフォームでGUIアプリケーションを作成する必要があるかもしれませんが、JDKに含まれるライブラリを考えると、Javaがオプションになる可能性がありますが、1つのターゲットプラットフォームにはJREがない場合があるため、代わりにCおよびSDL(または類似)を選択することもできます。

Cは一般的で小さく、高速であり、マシンコードにコンパイルされるため、このツールセットで重要な位置を占めています。また、太陽の下ですべてのプラットフォームでサポートされています(ただし、再コンパイルが必要です)。

要するに、できるだけ多くのツール、言語、およびパラダイムを学ぶ必要があります。

「私はXプログラマーです」(X = C、C ++、Javaなど)という考え方から離れてください。

「私はプログラマです」を使用してください。

プログラマーは、マシンにワークロードを実行するよう指示することにより、問題を解決し、アルゴリズムを設計します。物語の終わり。これは言語とは無関係です。あなたの最も重要なスキルは問題解決と構造化された問題の論理的な内訳であり、言語スキル/選択は常に二次的および/または問題の性質の結果です。

Cに興味がある場合の興味深い道は、Goでスキルセットを拡張することです。Goは、ガベージコレクションとインターフェイスを備えた優れたCであり、優れた組み込みスレッドモデル/チャネルであり、Cの多くの利点(ポインター演算やマシンコードへのコンパイルなど)ももたらします。


0

それはあなたがそれをどうしようとするかに依存します。Cは、アセンブリ言語の代わりとして設計されており、機械語に最も近い高レベル言語です。したがって、サイズとパフォーマンスのオーバーヘッドが低く、小さなフットプリントを必要とし、基礎となるハードウェアに近づくシステムプログラミングやその他のタスクに適しています。


0

最も効率的なアロケーターとデータ構造を効果的に実装するためにしばしば必要になる、データの生の同種のコレクションとしてのメモリのビットとバイトのレベルで作業しているとき、安全性はありません。安全性は主に強力なデータ型関連の概念であり、メモリアロケーターはデータ型では機能しません。ビットとバイトを使用して、同じビットとバイトをプールして、あるデータ型をある時点で表し、後で別のデータ型を表す可能性があります。

その場合にC ++を使用してもかまいません。あなたはまだstatic_castsコードからvoid*ポインタをキャストして散らばっていて、ビットとバイトを操作し、このコンテキストで型システムを尊重することに関連する面倒なことに対処します。memcpy型システムのブルドージングを心配することなく、ビットとバイトの周りに。

実際、C ++の型システムにブルドージングをして、 vptrsを上書きし、適切なタイミングでコピーコンストラクターとデストラクターを呼び出せない。これらのタイプを尊重し、新しい配置を使用してdtorなどを手動で呼び出すために適切な時間をかけると、RAIIにとって実用的ではない低レベルのコンテキストで例外処理の世界にさらされ、例外を達成できます。このような低レベルのコンテキストでの安全性は非常に困難です(ほとんどの関数が、すべての可能性をスローしてキャッチし、何も起こらなかったように分割できないトランザクションとして副作用をロールバックできるようなふりをする必要があります)。Cコードはしばしば「

そして、このようなアロケーターをここで「危険」にならない言語で実装することは不可能です。それらが提供するアロケーター(CまたはC ++で実装される可能性が最も高い)に頼らなければならず、それが目的に十分であることを願っています。そして、ほとんど常により効率的ですが、特定の目的に適した一般的ではないアロケーターとデータ構造がありますが、それらはあなたの目的に合わせて特別に調整されているため、はるかに狭く適用できます。

ほとんどの人は、元々CまたはC ++で実装されたコード、または場合によっては既に実装されているアセンブリを呼び出すことができるため、CやC ++のようなものを必要としません。多くの場合、個々のピクセルをループする最低レベルでそれほど革新を行っていないCで既に実装されている既存の画像処理関数のライブラリを使用する画像プログラムをつなぎ合わせるなど、高レベルで革新することで恩恵を受ける可能性がありますが、これまでにない非常に使いやすいユーザーインターフェイスとワークフローを提供します。その場合、ソフトウェアのポイントが低レベルのライブラリに高レベルの呼び出しを行うだけなら(「ピクセルごとではなく、この画像全体を処理し、何かを行う」)、それはおそらく時期尚早な最適化である可能性がありますCでそのようなアプリケーションの作成を開始することさえ試みます。

しかし、これまで見たことのないまったく新しい画像フィルターのように低レベルの方法でデータにアクセスするのに役立つ低レベルで何か新しいことをしている場合、それはリアルタイムでHDビデオを処理するのに十分速い少し危険です。

このようなものを当たり前のように考えるのは簡単です。私は、低レベルの言語が時代遅れになっているという意味でPythonを使用して3Dビデオゲームを作成することがどのように実行可能であるかを誰かが指摘しているFacebook投稿を覚えています。しかし、PythonはCで実装されたライブラリを高レベルで呼び出して、すべての面倒な作業を行っていました。既存のライブラリに高レベルの呼び出しを行うだけでは、Unreal Engine 4を作成できません。アンリアルエンジン4 図書館。他のライブラリやエンジンには存在しなかったあらゆる種類のことを、照明からそのノードブループリントシステムまで、そしてコードをその場でコンパイルして実行する方法まで行いました。低レベルのエンジン/コア/カーネルレベルで革新したい場合は、低レベルを取得する必要があります。すべてのゲーム開発者が高レベルの安全な言語に切り替えた場合、Unreal Engine 5、6、または7はなくなります。古いエンジンに高レベルの呼び出しを行うだけで、次世代エンジンを使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.