はじめに
「プログラムはなぜ動くのか」の第2版を読んでみたので自分なりの解釈と要点をまとめてみた。
どんな本なのか
「プログラムを実行しているときにコンピュータの中はどう動いているのか」がざっくり分かる本である。(まんまですね)
自分はプログラミング歴1年くらいだが、そんな自分でもかなり分かりやすく書いてあるので難易度的にはそこまで高くはないと思われる。
覚えておきたいこと
CPU、メモリ、ディスクの関係性について
CPU:プログラムを実行しているもの。実体はレジスタの集合体
メモリ:ディスクに保存されているプログラムを読み出す。
ディスク:プログラムの実体を保存しておく
レジスタとは処理対象となる命令やデータを格納する領域でメモリみたいなもの
メモリは1バイトずつにアドレスがついている。
CPUはこのアドレスを指定して、メモリに格納された命令やデータを読み出したり、書き込んだりしている。
ソースコードがCPUで解釈されるようになるまで
アプリケーションを構築しているソースコードはOSによってネイティブコードに変換(コンパイル)されてCPUで解釈される。
ソースコードとはCやJavaなどのプログラミング言語のこと
ネイティブコードとはCPUが理解できるコードのこと
CPUの種類によって対応するネイティブコードがある。
この辺の変換はOSがよしなに対応しているコードに変換してくれる
また、Javaの場合はコンパイルするとバイトコードと呼ばれるものに変換される。
バイトコードはJVMでネイティブコードに変換することができる。
なので対応するOSのJVMがあれば同じバイトコードをどの環境でも使うことができる。
また、ネイティブコードはソースコードに変換することはできない。
CPUにしか読めないネイティブコードを読みたいときはアセンブリ言語に変換する必要がある。
アセンブリ言語はネイティブコードと1対1に対応しており、人間でも読めるような記述で書かれている。
各章まとめ
1.プログラマにとってCPUとはなにか
CPUはレジスタ、制御装置、演算装置、クロックの4つの部品で構成されている。
ただ、プログラマが意識する必要があるのはレジスタだけで良い。
それは、プログラムはレジスタを対象として記述されるからである。
CPUは様々な役割を持ったレジスタの集合体である。
その中の一つのプログラム・カウンタは、プログラムをメモリに保存したあと、そのメモリのアドレスを順に設定してプログラムの流れを決めている
アキュムレータは値の比較に使ったりしている。
いろんなレジスタを使ってプログラムを処理している
2.データを2進数でイメージしよう
コンピュータの内部を構成しているICはピン1本で2つの状態しか表せないのでコンピュータは情報を2進数で取り扱う。
2進数のシフト演算は桁を左にシフトすることで2倍、4倍、8倍...となっていく。(逆もしかり)
2進数はマイナスの値を補数で表す。
例えば−1を8桁の2進数であらわすと、
1は「00000001」なので、−1は「11111111」(繰り上げて「(1)00000000」にするイメージ)
3.コンピュータが小数点の計算を間違える理由
2進数は「0.5」、「0.25」、「0.125」、「0.0625」でしか小数点を表せない
整数で計算してあとで小数に変換してあげる。
4.四角いメモリーを丸く使う
データ型とはメモリを保有するサイズのこと。
例えばcharは1バイト、shortは2バイト、longは4バイト
メモリを効率的に使うには配列を利用する
配列の変形手法には様々なものがある
スタックはLIFO(Last In First Out)、キューはFIFO(First In First Out)でメモリ内のデータを一時的に読み書きする。
スタックからデータを書き込む関数をPush、読み込む関数をPop
キューからデータを書き込む関数をEnQueue、読み込む関数をDeQueueという
他にもリストや二分探索木などもある
5.メモリーとディスクの親密な関係
仮想記憶:ディスクの一部を仮想的にメモリとして使う。
ディスク・キャッシュ:メモリの領域にディスクからのデータを保存しておき、高速に読み出す。
メモリを節約するには、
・ DLLファイルで関数を共有する
・ スタックのクリーンアップ処理を関数の呼び出される側で行う(処理を少なくする)
ファイルはディスクのクラスタと呼ばれるところに保存される
どんなにファイルサイズが小さくても1クラスタ分子容される。
1つのファイルを2クラスタに保存するみたいにまたぐことはできない
6.自分でデータを圧縮してみよう
ランレングス:文字×連続する文字数で表現して圧縮する
ハフマン:1文字1バイトではなく、ビットで表現して圧縮する
7.プログラムはどんな環境で動くのか
上の方に書いてある[「ソースコードがCPUで解釈されるようになるまで」](# ソースコードがCPUで解釈されるようになるまで)とほぼ同じ
8.ソース・ファイルから実行可能ファイルができるまで
EXEファイルの内容は、再配置情報、変数のグループ、関数のグループに分けられている。
ただし、プログラムがロードされたメモリ領域にはこれらの他に、スタックとヒープのグループが作られる。
スタック:ローカル変数や関数呼び出しの引数を格納するメモリ領域
ヒープ:プログラム実行時に任意のデータやオブジェクトを管理するためのメモリ領域
スタックのデータは自動でデータの格納と破棄(クリーンアップ)される
ただし、ヒープはプログラムで明示的に解放しないとメモリ・リークする
9.OSとアプリケーションの関係
システムコールとはプログラムでOSの機能を呼び出すこと。
timeやprintfなどがそうである。
アプリケーションはOSの操作、OSはメモリの操作を行う
10. アセンブリ言語からプログラムの本当の姿を知る
アセンブリ言語は3つのセグメントに分かれる
_TEXT:命令
_DATA:初期化されたデータ
_BSS:初期化されていないデータ
アセンブリ言語の構文は「オペコード+オペランド」である
オペコード:命令の動作
オペランド:命令の対象
11.ハードウェアを制御する方法
I/Oコントローラ:周辺機器とコンピュータをつなげるIC。このICのメモリをポートと呼ぶ
12.コンピュータに「考え」させるためには
ハンズオンぽくコードを書いていく章だったため割愛