優れたプログラマーになるには、ハードウェアレベルで何が起こっているのかを理解する必要がありますか?


24

私は独学のプログラマーです。CS101でこの質問に答えられる場合に備えて。私は多くの言語を学び、使用しました。

プログラミングの問題に遭遇したとき、私はいつも同じ壁にぶつかっているようです。たとえば、関数によって返された配列へのポインターを処理する方法について、別のフォーラムで質問をしました。最初は、C ++の設計者が状況を処理するために設定した適切なテクニックがわからないだけだと考えています。しかし、以下の回答と議論から、何かが「返品」されたときに何が起こるかは本当にわかりません。

優れたプログラマーは、プログラミングプロセスをどの程度深く理解する必要がありますか?


3
私のアドバイス:x86アセンブリ(DOSまたはその他)を学んでください。次に、いくつかの小さなCコードのアセンブラ出力の一部を読むことを学びます。出力が理解できない場合は質問してください。繰り返す。これにより、CPUレベルで何が起こっているのかを理解する必要があります
-Earlz


Earlz-x86命令セットを使用したプログラミングを学ぶ必要があるということですか?それは「CPUレベル」ですか?
ベブ

仕事-thx、それは楽しかったです。実際、彼はいくつかのエラーを犯しました。
ベブ

回答:


33

いいえ。ハードウェアレベルで何が起こっているのか誰も理解していません。

コンピューターシステムはタマネギのようなものです。多くの層があり、それぞれがその下の層に依存してサポートされています。あなたが外層の1つで作業している人であれば、タマネギの真ん中で何が起こるかをあまり気にするべきではありません。タマネギの真ん中は常に変化しているので、それは良いことです。特定のレイヤーをサポートするレイヤーが同じように見え、レイヤーをサポートしている限り、あなたは大丈夫です。

しかし、再び...

はい。つまり、タマネギの内部で実際に起こっているのを理解する必要はありませんが、典型的なタマネギの内部がどのようなものであるかの精神モデルを持つことは大いに役立ちます。おそらく、トランジスタなどで構成されたゲートを持っている最深部ではなく、マイクロコード、クロック、命令デコードユニットなどを持っている次の層または2つです。しかし、次の層は、レジスタ、スタック、ヒープがあります。これらは、何が起こるかに多くの影響を与える最も深い層です。コンパイラは、コードをこのレベルで実行される命令に変換します。

ほとんどの経験豊富なプログラマーは、頭の中にこれらのレイヤーの少しおとぎ話のようなバージョンを持っています。これらは、コンパイラが「無効なアドレス例外」または「スタックオーバーフローエラー」などが発生したことを通知するときに、コンパイラが何について話しているかを理解するのに役立ちます。

興味のある方は、コンピューターアーキテクチャに関する本を読んでください。特に新しい本である必要はありません。デジタルコンピューターは、ほぼ同じように長い間機能しています。タマネギの内部について学べば学ぶほど、このようなものが機能することに驚くでしょう!下位層で何が起こっているかを(およそ)学習することで、プログラミングの神秘性が低くなり、何らかの形で魔法のようになります。そして本当に、もっと楽しい。

あなたが検討するかもしれないもう一つは、埋め込み玉ねぎです。えー、私は組み込みシステムを意味します。非常に使いやすい多くの組み込みプラットフォームがあります。ArduinoBASIC Stampは2つの例です。これらは基本的に、多くの組み込み機能を備えた小型のマイクロプロセッサです。通常のデスクトップPCよりもレイヤー数の少ないタマネギと考えることができます。そのため、ハードウェアからソフトウェアに至るまで、システム全体で何が起こっているのかを完全に理解することができます。


2
ありがとう。これは基本的に私の質問に答えます。私は、レジスター、加算器、マルチプレクサーなどのチップレベル(つまり、トランジスターレベル)の設計を行ったEEなので、最低レベルになります(量子力学の話をしていない限り)。私もかなりよく知っている言語を使用できます。中間レベル(スタック、ヒープ)には大きなギャップがありますが、ここではコンパイラーが作業を行うと言います。あなたが言ったように、私は私のプログラミング体験が「神秘的でなく、...、より魔法的」であることを望んでいます。まだ知られていないレベルを研究する必要があるようです。
ベブ

@bev:その場合、Arduinoのようなプラットフォームを実際にチェックアウトする必要があります。
カレブ

退屈して申し訳ありませんが、Arduinoをチェックアウトしました。Arduinoを使用すると、コンパイラがポインターと配列を異なる方法で処理する方法を理解するのにどのように役立つかわかりません。何が見えないのですか?
bev

@bev:関数がどのように呼び出されるかを知りたいだけなら、おそらくそれを読んで30分を費やして完了です。すべてがどのように連携するかをよりよく理解したい場合は、小さなシステムで最も簡単になります。タマネギ全体を一度に摂取するのに最適な方法です。ArduinoのベースとなっているチップファミリであるAVRは、問題なく学習できるほど十分に小さい命令セットを備えた、優れた汎用の使いやすいシステムです。
カレブ

ああ、わかった。ホームページは、製品のその側面については少し曖昧です。もう一度見ます。
bev

10

ハードウェアレベルの話ではなく、コンパイラーが指示どおりにコンパイラーが実際に行うことについて話しています。

特にメモリストンプの状況に対処する場合、明らかでない場合に何が問題になったかを把握するには、このレベルの理解が必要です。


ローレン-はい!単純な真実をありがとう。ここで、C ++コンパイラがデータ型をどう処理するかを知る最良の方法を見つけ出す必要があります。ところで、EEとして、私はそれが文字通りハードウェアレベルではないことを知っています。私はあなたのCSオタクがそれを何と呼ぶか​​知りませんでした。(それでも問題はありません。コンパイラレベルですか?)
bev

ところで-メモリストンプ?
bev

@Bev:あなたはここで私のポイントを証明しました-メモリストンプが何であるかさえ知らなければ、あなたは1によるバグを見つけるのにひどい時間を過ごすでしょう。メモリーストンプとは、想定外の場所に何かが書き込まれ、そこに起こったものをすべて消去する(踏みつける)ことです。運が良ければ、ヒットしたものはすぐに不可欠であり、少なくとも爆発します。運が悪ければ、プログラムはデータの一部に穴を開け続けるだけです。
ローレンペクテル

説明をありがとう。また、私が知る限り、より細かい制御なしにヒープまたはスタックに書き込むだけなので、どれだけ知らないかを示します。
bev

@Bev:自分が書いているとは思わない場所に書くときに問題が発生します。スタックに何かがあり、それへのポインタを作成します。ルーチンを終了します。アイテムは消えますが、ポインターは消えません。そのポインターに書き込むとどうなりますか?または、100個のアイテムの配列がある場合、アイテム#200に書き込むとどうなりますか?
ローレンペクテル

6

プログラムメモリについて!=ハードウェアについて

メモリ階層を理解する==ハードウェアを理解する


あなたの一般的な質問に答えるために:それは依存します。ハードウェアを理解しても害はありませんが、それを理解してもすべての場合に役立つわけではありません。

例に基づいて、プログラムの実行時にメモリがどのように分割され、どのように構成されているかについてさらに理解する必要があります。ハードウェアを理解することは、この点では役に立ちません。なぜなら、メモリ(プログラムから見える)は、仮想メモリの魔法のおかげでハードウェアを実際に表すことすらできないからです。

メモリにアクセスする順序に基づいてパフォーマンスの問題に興味がある場合は、ハードウェア、メモリの階層、キャッシュミス、ページフォールト、およびハードウェアから得られるすべての素晴らしい素晴らしい長所を理解することから恩恵を受けるでしょう。


Stargazer-パフォーマンスの問題を心配できる時点ではまだありません。すぐに、うまくいけば。コメントありがとうございます。
bev

5

あなたがいる場合、アセンブラのビットを学ぶことを決定、あなたはおそらくアミーガの6502コモドール64(もちろん、エミュレートされた)上のアセンブラ、または68000のような何かを学ぶ必要があります。

Commodore 64については、こちらをご覧ください...

http://thepiratebay.org/torrent/4609238/Tag3-Saal2-Slot16_00--ID2874-the_ultimate_commodore_64_talk-Main

知っておくべき古典的な本は、ここで説明されているものです...

http://reprog.wordpress.com/2010/03/12/programming-books-part-3-programming-the-commodore-64/

周りを見ると、おそらくPDFスキャンを見つけることができます。

IMO、6502はZ80よりも簡単で、68000は8086よりも簡単です-より一般的な命令セットなど

ただし、CPUはハードウェアの1つの側面にすぎません。また、最新のCPUは大きく異なる獣であり、仮想アドレス空間の提示など、コンパイラーの観点からも透過的なことを行います。

C64での6502の特別な利点は、CPUが単純であるだけでなく、ハードウェアで簡単にハックアラウンドできるものがあることです。私はかつてSIDミュージックチップをいじってとても楽しかった。

ですから、あまり時間をかけなければ、おそらく価値のある運動になります。Commodore Basicの直後、14歳のときに6502アセンブラーを第二言語として学びました。しかし、ほとんどの場合、非常にシンプルな作業モデルを取得しているため、誤解を最小限に抑えながら、より洗練されたアイデアを追加できます。

アセンブラでの作業を学ぶことができるいくつかの有用なもの...

  • CPUレジスタの動作方法。
  • インダイレクションを含むメモリアドレッシングの仕組み。
  • CPUスタックの仕組み。
  • ビットごとの論理の仕組み。
  • CPUがI / Oデバイスを制御する方法。
  • 割り込みの仕組み。

私が推奨する特定の理由の1つは、知性や常識がなくても、単純なステップが完全に決定論的かつ機械的かつ完全に動作する方法のより良い直観を得ることです。基本的に、最も純粋で最も頑固に無知な形式の命令型実行モデルに慣れる。

正確にどのようにそれは今それらのもののほとんどを知っている便利な、しかし、難しい質問です。

あなたが学ばないことの1つは、記憶階層でうまく遊ぶ方法です。これらの古いマシンには、キャッシュ層も仮想メモリもないシンプルなメモリモデルがほとんどありました。また、並行性についてはあまり学習しません-それらは確かにそれを処理する方法でしたが、それはほとんど割り込みを意味していました。ミューテックスなどを心配する必要はありませんでした。

時には、これらの事柄がかつてどのように機能したか、またはアセンブラーがどのように機能したかの精神モデルが誤解を招く可能性さえあります。たとえば、Cポインターをアドレスと考えると、未定義の動作の問題が発生する可能性があります。通常、ACポインターはアドレスを含む整数として実装されますが、それが厳密に正しいという保証はありません。たとえば、一部の奇妙なプラットフォームでは、異なるポインターが異なるアドレス空間を指す場合があります。これは、2つのポインターで算術演算またはビットごとの論理演算を行う場合に重要になります。

これらの奇妙なプラットフォームのいずれかを持たない限り、あなたはそれを気にかけないと思うかもしれませんが、最近のコンパイラは最適化のために標準未定義の動作を悪用する可能性がますます高くなっています。

したがって、システムアーキテクチャのメンタルモデルは有用ですが、言語とプラットフォームが尊重しない仮想モデルではなく、言語仕様に合わせてコーディングすることが重要です。

最後に、コンパイラがコードを生成する方法を理解することから、多くの有用なメンタルモデルが得られます。また、現代の言語のコード生成は、当時利用可能な非常に単純なコンパイラとは大きく異なります。

これは私のお気に入りの本です...

http://dickgrune.com/Books/MCD_1st_Edition/

構文解析やASTなどに関するものに加えて、さまざまな言語パラダイム(命令型、OOP、関数型、論理型、並列型、分散型)のコード生成、およびメモリ管理もカバーしています。CPU命令セットの詳細に行き詰まることなく、ポリモーフィックメソッド呼び出しがどのように機能するかを知りたい場合は、このような本があなたの友人です。まもなく公開される新しいエディションがあります。


スティーブ-すごい。私の質問に対するあなたの答えの完全性と焦点については、私はほとんど言葉になりません。このすべてを書いてくれてありがとう。私は間違いなくあなたの提案を取るでしょう。
bev

1
PDP-11アセンブラーは、他のすべてのアセンブラーよりも学習するのが少し良いと思います。他のすべてが教えることは、より限られたハードウェアリソースによって、および/またはより限られたハードウェア設計と先見によって強制された制限です。あまりにも一般的な8051ファミリーのようなものは、プログラミングモデルがそのような限られたハードウェアでいかに奇妙なものになるかを教えています(たとえば、異なるアドレス空間についてのスティーブの言及が出てくる)。
グレッグA.ウッズ

@Greg-PDP-11でプレイすることはなかったのですが、怖いです。8051でもありません-しばらくの間、いくつかの組み込み作業を行いましたが、それは8096ファミリチップを使用していました。私はただここをいた-面白い。ハーバードアーキテクチャについてはしばらく前に聞いたことがありますが、非常に人気があり、まだ使用されているこのようなものがあるとは思いもしませんでした。
Steve314

4

20年前は重要でしたが、今はそれほど重要ではありません。ソフトウェアと最新のハードウェアの間には、さらに多くの抽象化レイヤーがあります。

複数のコアを利用するために複数のスレッドが必要なことや、システムに存在するよりも多くのメモリを使用することは悪いことですが、それ以上は、それらの抽象化を書くのがあなたの仕事でない限り、本当に必要ではないことを知ることは有用です層。

質問の残りの部分は、ハードウェアよりもコンパイラに関心があるかもしれないことを示唆しています。これは少し異なります。あなたはそれが重要なケースに出くわすかもしれませんが、これらは些細な(無限再帰はあまりうまく動作しない)傾向があるか、あなたはそれを解決することについて良いと感じることができるがおそらく同じ問題には決して出会わないでしょう再び。


はい、あなたは正しいです、私はコンパイラにもっと関心があります。また、複数のスレッド、複数のコアなどについての提案のthx。これは、私のtoLearn notesファイルに含まれています。
bev

@bevマルチスレッドは簡単に習得できます。本当に必要な場合を除いてはいけません。私の経験ではその価値以上のトラブル。
スケイス

@Skeith-ヒントをありがとう。心に留めておきます。
bev

4

ハードウェアによって提示される抽象化と、その幻想がどのように作成されるかについての一般的な考え方を少し知って理解するのに役立ちますが、現代のハードウェアが実際にどのように機能するかを真に理解しようとすることは、膨大な量の作業です最小限のリターンのみが見られる可能性が高い。

ちょっとした転用を許してくれるなら、これは数年前に私が指摘したことを思い出させてくれます。数十年前(1970年代後半まで)、ほとんどの人はコンピューターは魔法の一歩手前であると考えていました-物理法則の影響をほとんど受けず、ほとんど意味をなさないあらゆる種類のことができる、などなど。当時、私はかなりの時間を費やして、ほとんどの場合失敗しました。そうではない、彼らは魔法ではないと人々に納得させました。それらは、ごく普通のマシンであり、限られた数の処理を非常に迅速かつ確実に行いましたが、それ以外は非常にありふれたものでした。

今日、ほとんどの人々のコンピューターの見方は変わりました。彼らは今ではかなり普通です-非常に少数の非常に普通の人々がそれらを実際に把握しているという点まで。ちょうど例えば、私が夕食を食べている間、ウェイターとウェイトレスが休憩中に彼女が彼女の新しいコンピューターで何を手に入れるべきかを話し合っているのを見た/聞いた。彼が与えていたアドバイスは完全に合理的で現実的でした。

私のコンピューターの見方も変わりました。私はHot Chipsに行きましたが、その前にマイクロプロセッサフ​​ォーラムは1990年代半ば頃に戻りました。私はおそらくより多くのマイクロプロセッサのハードウェアに関するプログラマの少なくとも99%よりも知っている-と私は何をすべきかを知って、私はこれを言うだろう:彼らはしているではないもう普通。彼ら物理学の法則をほとんど破りません。私は多くの低レベルのテストを行ってきましたが、これは確かに言えることです。CPUによって作成された錯覚を通り過ぎて、ハードウェアが実際にどのように動作するかを示すレベルに到達することは、しばしば信じられないほど困難です。私はちょうど適切に測定するために、私はノー未満4ロジック・アナライザからケーブルの下に埋もれコンピュータと私たちの設定のいずれかの画像を投稿することがしたいものを キャッシュが最新のCPUでどのように機能するかの側面(測定したものがCPUの動作とまったく同じであることを保証するための真に厳格なプログラミングは言うまでもありません)


ジェリー-コメントありがとう。EEであるため、より高い抽象化レベルのいくつかよりもトランジスターレベルの方が安心です。私は本当に良いC ++プログラマーになるために何を知る必要があるのか​​と思っています。
bev

その写真は面白いですね。なぜ投稿できないのですか?
メイソンウィーラー

@Bev:優れたプログラマーになるために、トランジスタレベルで何も知る必要はありません。これらの抽象化には理由があり、マシンコード/アセンブリの抽象化レベルより下の抽象化レベルのすべてのものは、完全に無関係であり、それが機能すると仮定することができます。
メイソンウィーラー

@MasonWheeler:私は以前働いていた場所でそれを取りましたが、私はそこでそこで働いていないので、それにアクセスすることはおそらくもう少し難しいでしょう(おそらく不可能ではない-私は良い条件で辞めますが、そうであっても)。 ..)
ジェリーコフィン

1

異なる言語は、ハードウェアからの抽象化の異なるレベルで機能します。CおよびC ++は非常に低レベルです。一方、スクリプト言語では、基礎となる詳細についてあまり知識を必要としません。

しかし、すべての場合において、あなたが知っているほど、プログラマーは良くなると私は言います。プログラミングの一部は、複数の抽象化レベルを同時にジャグリングできることです。

C ++でプログラミングしている場合、少なくともコンパイラーが動作する抽象化レベルで、最新のCPUがどのように動作するかを十分に理解する必要があります。(CPUの内部では、コンパイラに対して透過的なことが行われています)。


スコット-「最新のCPUの仕組みをかなりよく理解している」とは、デジタルロジックの仕組み(たとえば、カルノーマップ、真理値表、AND / OR / NOR / XORゲートの仕組み)を意味しますか?または、コンパイラが直接使用するリソース(つまり、レジスタ)を意味しますか?
bev

もっと知ることは良いことです。しかし、本当のトリックは、どのような種類の「もっと」があなたの支出に最大の価値を与えるかを知ることです。たとえば、命令のタイミングを知ることは、コンパイラが使用する命令を予測することがほぼ不可能な場合、あまり役に立ちません。プロファイラの使用方法を学習することで、コスト/ベネフィット比が大幅に向上する可能性があります。
Steve314

1
@bev-いいえ、ゲートレベルに到達する必要はないと思います。基本アーキテクチャ(メモリ、バス、CPU)、命令のロード方法、実行方法、結果の保存方法などを知っていれば、おそらく大丈夫です。また、コンパイラがスタックとヒープを使用する方法など、プログラムのメモリ空間をレイアウトする方法を理解する必要があります。
スコットホイットロック

@ScottWhitlock-ありがとう-これは私が探していた特定の推奨事項の一種です。
-bev

0

Cのような高レベル言語の全体的な設計についてポイントを追加したいと思います。

一般に、そのような言語は抽象マシンを実装していると見なすことができると言っても安全だと思います。実際、デニスリッチー自身がCの仕組みと、Cの抽象マシンの特定の設計によってよりポータブルな言語になった方法を説明していると言えます。そのため、コンピュータアーキテクチャとマシンレベルの機能をある程度理解していると、言語の抽象的なマシンを理解する上でも非常に役立ちます。

DMRのCプログラムとUNIXシステムの移植性は、Cの(抽象的な)マシンモデルについて最初に説明したものです。

Cの歴史と開発に関するDMRの論文は、実際のハードウェアが言語設計にどのように影響するかを示すのに非常に役立ち、おそらく初期のプログラミング言語設計の例でもあると思います: C言語の開発


ここは初めてなので、これはフォーラムだと思うようですが、間違いなくそうではありません。質問への回答は、追加するポイントであってはならず、コメントに委ねるべきであり、回答は質問に対する直接的な包括的回答であるべきです。それはあなたが良い点を述べており、これはトピック情報に価値があると言いました。おそらく、この説明と一緒に質問に直接答えることができれば素晴らしいでしょう。ここで共有しているクールな情報。プログラマーへようこそ!
ジミー・ホッファ

コメントはバージョン管理されておらず、永続的でもないため、一連の回答に追加しても意味がありません。ほとんどのポスターは、コメントの使用を無視して回答を更新する傾向があり、ほとんどの回答は「コミュニティWiki」の回答としてタグ付けされていないため、他の投稿者への帰属を維持するような方法で他者が編集することはできません。その上、この特定の質問は真の議論を始めました、そして、それが好きかどうかは、これらの事柄のいくつかが行く方法です。すべての貢献を1つの型に強制しようとすることは、スタック交換の概念の大きな失敗です。
グレッグA.ウッズ

そしてところで、私は実際にOPからの1つの本当の質問に暗黙のうちに答えました。言語設計の中核にある抽象マシンをモデル化できるハードウェアの十分な理解が必要です。
グレッグA.ウッズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.