「プログラムはなぜ動くのか」を読んだ

プログラムはなぜ動くのか 第2版 知っておきたいプログラムの基礎知識

プログラムはなぜ動くのか 第2版 知っておきたいプログラムの基礎知識

プログラムを書き始めて5年ほど経つが、今までずっと「何かアプリケーションを作る」という目的のためだけにソフトウェアを作ってきて、それゆえに低レイヤで何が起きているのか全然知らなかった。
プログラムを書くのにコンパイラが何をしているのかわからんのもよくないので、そこらへんを知りたくて読み始めた。

CPU から2進数、メモリ、コンパイラ、OS、アセンブラと今まで避けてきたことが色々書いてあった。

特にコンパイラアセンブラの章がよかった。
コンパイラは色々ゴニョゴニョっとライブラリ入れたりスタティックライブラリ使ったりとかしてやっと exe ファイルができるらしい。
アセンブリ言語も mov とかでチョチョっと書ける、逆アセンブルというのはマシン語アセンブリ言語に逆変換することだったのか、それすら知らなかった。

2進数とかってどうなんだろうか、どの程度まで理解していた方が良いのだろうか。あの 1001010101 みたいな数字が苦手で、 2進数を10進数に計算するのもろくにできない。
でもそれで困ったことがないと感じてて、それは私のレベルが低いから困ったことがないだけで他の人は2進数の理解によりメリットを感じているのだろうか。

本の内容としてはためになったけど、この本を読む前とあとで自分の書くコードは変わらないのかな、とも思う。
コンパイラを理解しているとデバッグがしやすいとか書いてあったけど、果たして iOS の Swift などでそれが役に立つことがあるのだろうか…。
自分の理解度が低いのか、時代に即していないのか、果たして。

とはいえ、ためになるいい本でした、終わり。

以下 wikihub 日報 のまとめ。


読み始めた。いつだかに買ったけど積んでたやつ。 ソフトウェアは書けるけどなぜ動くかわかっていないのでためになる気がする。 1章読んだけど全然わからんかった、パソコンは難しい。

  • レジスタ
    • 命令やデータを格納する領域でメモリみたいなもんらしい
  • 制御装置
    • メモリ上の命令やデータをレジスタに読み出し、命令の実行結果に応じてコンピュータを制御するらしい
  • 演算装置
    • メモリからレジスタに読み出されたデータを演算するらしい
  • クロック
    • CPU が動作するタイミングとなるクロック信号を発生させるもんらしい
    • クロックは大きければ大きいほど CPU は早い
  • みなさんが書いたコードがマシン語となり CPU の内部でレジスタを使った処理結果になるらしい
  • コール命令やリターン命令で関数を実行したりするらしい
  • この本を読むと今まで何気なく書いていたプログラムがこれからは生きたものに見えてくるようになるとのこと

備忘録として書いてたらめっちゃ長くなった。

2章 データを2進数でイメージしよう

2進数めっちゃ苦手だ。というか知らなくてもプログラム書けないですか?

  • ビット
    • 2進数の1桁に相当する
  • バイト
    • 8桁の2進数
  • 基数
    • 数の数え方、10進数は10を基数、2進数は2が基数
  • シフト演算
    • 2進数で表された数値の桁を左右にシフトする
    • シフト演算や論理演算の仕組みをイメージできることは 必ず 身につけておかなければならないこと
      • まじ?
  • 符号ビット
    • 0の場合はプラスで1はマイナス
  • 補数
    • プラスの値でマイナスの値を表す
    • 「反転して +`1」で補数を求める
  • 論理右シフト
    • シフト後の上位桁に0を入れる
  • 算術右シフト
    • シフト前の符号ビットの値を入れる?
  • 符号拡張
    • 例えば8桁の2進数を、値を変えずに16桁や32桁の2進数に変換すること
  • 算術演算
  • 論理演算
    • NOT,AND,OR,XOR など
  • 真理値表
    • 2進数の0がfalseで1がtrue

3章 コンピュータが少数点数の計算を間違える理由

計算とかだいたい Math.floor とかしちゃうから気にならないくないですか?

  • 0.1 を 100 回加えても10にならない
  • 10進数の小数点の中には、2進数に変換できないものがある
  • 正確に表せない数は近似値になってしまう
  • 倍精度浮動小数点型
    • 64 bit の double
  • 短精度浮動小数点型
    • 32 bit の float
  • 浮動小数点では、少数点数を「符号」「仮数」「基数」「指数」の4つに分ける
  • 符号部
    • 1bit を使って数値の符号を表す、0は負で1は正
  • 仮数
    • 様々な形式で表せる浮動小数点型を糖質的な表現にする
  • 指数部
    • イクセス表現を使う。
    • 中央の値をゼロと見做すことでマイナスの値を表す工夫、トランプでいうと7を中心とし6以下はマイナスみたいな

4章 四角いメモリーを丸く使う

メモリに関しての内容。
C言語も書いたことないしポインタとか概念としてしか理解してない。

  • 制御信号
    • WR(write), RD(read) のように IC に動作を行わせる信号
  • メモリの物理的な仕組み
    • モリーIC の内部に8ビットデータを格納できる入れ物がたくさんあり、その場所をアドレスで指定してデータの読み書きを行うだけ
  • データ型
    • どのような種類のデータを格納するか示すもので、メモリからすると占有するサイズを意味するもの
  • 変数を使うことで物理アドレスを指定しなくてもプログラムでメモリの読み書きが可能
  • ポインタ
    • データの値そのものでなく、データが格納されているメモリーのアドレスを持つ変数
    • 参照型って理解でいいのかな?
  • 配列
    • 同じデータ型の複数のデータがメモリ内に連続して並んだもの
  • スタック/キュー
    • どちらもアドレスやインデックスを指定せずに配列の要素を読み書きできるもの
  • スタック
    • LIFO = Last In First Out
  • キュー
    • FIFO = First In First Out
  • リスト
    • データの値だけでなく、次の要素のインデックスも付加できる
    • リストでない配列を使うと、途中の要素を消した時に後ろの要素を全て移動しないといけない

ためになる!

5章 メモリーとディスクの親密な関係

メモリとディスク(HDDとかフロッピーとか)について。

  • ストアド・プログラム方式
    • プログラムが記憶装置に格納されていて順次読み出されて実行される仕組み
    • この方式の前はコンピュータの配線を変えてプログラムを変更してていたらしい
  • ディスクキャッシュ
    • 一度ディスクから読み出されたデータを保存しておくメモリ内領域
  • 仮想記憶
    • ディスクの一部を仮想敵にメモリとして使うもの
    • 物理メモリと仮想メモリスワップしながらプログラムを実行する
  • ページング方式
    • 実行されるプログラムを構造に関係なく一定の「ページ」の大きさに分割する
    • ページイン、ページアウトとかいう
  • ページングファイル
    • 仮想記憶を実現するためにデゥスク状に仮想メモリとなるファイルをおく
  • スタティックリンク
    • アプリケーションの実行ファイルの中に関数を埋め込むこと
    • これをやると同じコードが複数アプリケーションに存在することになり微妙っぽい
  • スタックのクリーンアップ処理
    • 関数の引数を受け渡すために使われるメモリ状のスタック領域から不要となったデータを削除すること
    • 関数の前に _stdcall をおく
  • ディスク
  • セクター方式
    • 固定長の領域に区切る
    • ディスクの表面を同心円状に区切った領域をトラックと呼び、それを固定長サイズに区切った領域をセクターと呼ぶ
    • 複数のファイルを1つのクラスタに格納はできない、両方削除されちゃう
  • バリアブル方式
    • 可変長の領域に区切る

6章 自分でデータを圧縮してみよう

zip とかの仕組みが書いてあって面白い。

  • ランレングス法
    • ファイルの内容をデータ*繰り返し回数で表すことで圧縮する方法
    • 同じデータが続いている場合が多い画像ファイルなどでは有効打が文書ファイルではあまり…
  • ハフマン法
    • よく使われるデータを判別して、それを小さいbit数で表す
    • ハフマン木とか使う
  • BMP
    • bitmap は圧縮していないやつ
  • 可逆圧縮
    • 元に戻せる、zipとか
  • 非可逆圧縮
    • 元に戻せない、jpeg とか

7章 プログラムはどんな環境で動くのか

戦うプログラマーでいろんな環境で動くように作るみたいな話をしていたやつだった。

  • ネイティブコード
  • ソースコード
    • テキストファイルで書かれたやつ
  • アプリケーションの機能の中に、ハードウェアを直で触るところがあると汎用プログラムにならない
  • API
    • Application Programming Inteface
  • Ports
  • Java
  • JVM
  • BIOS
    • ROM に記憶され、キーボードとかの基本制御プログラムやブートストラップ・ローダーをもつ
  • ブーとストラップ・ローダー
    • 起動ドライブの先頭領域に記憶された小さなプログラム
    • OS はブーとストラップ・ローダーによって起動する

8章 ソース・ファイルから実行可能ファイルができるまで

コンパイラとかのはなし。
知らないことばっかりだ。

  • ダンプ
    • ファイルの内容を1バイトずつ2桁の16進数で表示すること
  • ロスコンパイラ
    • 動作環境で使われる CPU とは異なる CPU 用のマシン語を生成
  • オブジェクトファイル
    • コンパイルした後に生成される .obj 形式のファイル
    • まだ exe ファイルではない
    • printf() など実行する場合は必要な処理内容が格納された状態に結合しないといけない
  • リンク
    • 複数のオブジェクトファイルを結合して1つのexeファイルを作る処理
    • リンクを行うプログラムのことをリンカーという
  • スタートアップ
    • 全てのプログラムの先頭に結合する共通的な処理が書かれたオブジェクトファイル
  • ライブラリファイル
    • 複数オブジェクトファイルをまとめて1つのファオルに格納したもの
  • 外部シンボル
    • 他のオブジェクトファイルの中にある変数や関数
    • printf() とか
  • 標準関数
    • ライブラリファイルの形式でコンパイラと一緒に提供される
  • DLL
    • Dynamic Link Library、プログラムの実行時に結合されるもの
  • インポートライブラリ
    • 外部にあるライブラリファイル
  • スタティックリンクライブラリ
    • exe ファイルに直接結合するライブラリファイル
  • 再配置情報
    • 実行時にメモリを仮想敵に与えてうまく動くようにするやつ
  • スタック
    • 関数の内部で一時的に使用される変数などのメモリ領域
    • 自動でメモリを確保し自動で解放
  • ヒープ
    • プログラムの実行時に任意のデータやオブジェクトを格納するためのメモリ領域
    • 自分でメモリを解放する

コンパイラはこんな感じの処理になるっぽい。

ソースファイル
-> .obj + タートアップ + スタティックリンクライブラリ + インポートライブラリ
-> スタティックリンク + ダイナミックリンクライブラリ
-> exe


読み終わった。

9章 OS とアプリケーションの関係

  • モニター・プログラム
    • プログラムをロード・実行する機能だけを備えるやつ
  • OS 上で動くアプリはハードウェアを OS を介し間接的にアクセスする
  • システムコール
    • OS の関数とかを呼び出す行為
  • 時分割
    • 短い時間間各区で複数のプログラムを切り替えながら実行する
  • マルチスレッド
    • 関数の単位で時分割を行う
  • ミドルウェア
    • ネットワークやデータベース機能のような、OSには不可欠でないがOSに近い存在のこと
  • システム・ソフトウェア
  • フラグ&プレイ
    • 新しいデバイスをすぐに使えるようにする仕組み
  • バイス・ドライバ
    • 新しいデバイスを接続した時にそれを制御するプログラム

10章 アセンブリ言語からプログラムの本当の姿を知る

この本で一番ためになる章だったと思う。
コードがコンパイルされ、それがどうコンピュータに読まれるかみたいなのを順を追って解説してくれる。

11章 ハードウェアを制御する方法

  • システムコールを使いアプリケーションからハードウェアを制御する
  • IN命令
    • 指定したポート番号のポートからデータを入手する
  • OUT命令
    • CPU のレジスタに格納されているデータを指定しポート番号のポートに出力
  • I/Oコントローラ
    • コンピュータ本体と周辺装置をいい感じに繋ぐやつ?
  • ポート
    • 入出力されるデータを一時的に格納しておくための一種のメモリ
    • えっポートってメモリなの、マジで
    • ポートって行っても https:443 みたいなポートとか USB ポートとか色々あるし何がどれなんだ
  • ポート番号
    • I/Oアドレスとも呼ぶ。ポートを区別するやつ。
  • IRQ
    • Interrupt Request, 割り込み要求
  • 割り込み処理
    • 現在実行中のプログラムを一旦止めて他のを実行する
    • 割り込み番号が振られる
    • 割り込みコントローラが間にいる
  • ポーリング
    • 複数の周辺装置の状態を順番に調べること。パソコンには不向き
  • DMA
    • CPU を仲介せずに周辺装置が直接コンピュータのメインメモリとデータ転送をおこなう
    • DMAチャネル
  • I/Oポート番号、IRQ、DMAチャネルは周辺装置を識別するための3点セット
  • VRAM
    • ディスプレイに表示される情報を記憶するメモリ

12章 コンピュータに「考え」させるためには

プログラムに人間の傾向とかを学ばせるみたいな話。
ディープラーニングみたいに深い話ではなく、人間がグーを出した後はパーを出しやすいとかを覚えるとかの話。

  • 擬似乱数
    • 数式によって得られる乱数、本当の乱数とは言えない