C++プログラミング #1 データとメモリ
- Lingheng Tao
- 2024年1月13日
- 読了時間 7 分
Algorithms & Data Structure Content List C++ Programming Content List Unity Shader Content Table
#ComputerScience#GameProgramming
このノートは C++ の数値型とメモリ管理に関する知識点をまとめます。
変数型
カバーする可能性のある変数型は上記の通り。本稿では、バイト(byte)は 8 ビットのメモリ単位、つまり 1 byte = 8 bits を指す。
単純変数
分類
- 整数型:char (1 byte), short (2 bytes), int (4 bytes), long (4 bytes), long long (8 bytes)。
- 浮動小数点型:float (4 bytes)、double (8 bytes), long double (12 or 16 bytes)。
特に、ブール型(bool)の値は true と false のみ。C++ は 0 を false、非ゼロ値を true と解釈する。
C++11 は固定幅整数型 int16_t, int32_t, int64_t を提供。長さはそれぞれ 16 bits, 32 bits, 64 bits(2/4/8 バイト)。
表現
整数型の表現:
- 符号付き(signed)の場合、第 0 ビットは常に正負(1=負、0=正)を表し、それ以外のビットで数値の大きさを表す。
- 符号なし(unsigned)の場合、全ビットで大きさを表す。
float (32 bits) の表現:
- 第 0 ビット/符号ビット(1 bit):正負。1=負、0=正。
- 第 1-8 ビット/指数ビット(8 bits):数値範囲。
- 残り/仮数ビット(23 bits):精度。
例:-15.5 を二進数で表現する。
- 符号:負なので最初のビットは 1。
- 絶対値:15.5 = 15(int) + 0.5(decimal)
- 二進変換:15 = (1111)_2, 0.5 = 1/2 = 2^(-1) = (0.1)_2
- オフセット:15.5 = (1111.1)_2 = 1.1111 * 2^3, offset = 3+127 = 130 = (10000010)_2
- 仮数:1.1111 → .1111 → (23ビットにパディング) (11110000000000000000000)_2
全パーツを結合:-15.5 = (1 10000010 11110000000000000000000)_2
Double (64 bits) の表現:
- float と同じ計算手順。
- 符号ビット 1 ビット、指数ビット 11 ビット、仮数ビット 52 ビット。
型変換
C++ はある型の値を別の型の変数に代入することを許可する。
一般的に、より大きな値域の型への変換は問題を引き起こさない(例:int から long へ)。しかし、大きな long 値を float に変換すると精度が低下する。float は有効数字 6 桁のみ。
より大きな値域から小さい値域への変換(かつ実際に範囲を超える場合)、通常は右側のバイトのみがコピーされる。
メモリ
メモリ(Memory)はコンピュータの記憶領域で、プログラムの命令、データ、状態を格納する。主記憶は M 個の連続したバイトサイズのユニットからなる配列として構成され、各バイトに一意の物理アドレスがある。
8 ビットを 1 バイトとし、バイトはメモリアドレッシングの最小単位。各バイトの番号は一意で、アドレスで正しいバイトにアクセスできる。
メモリアドレス空間
アクセス可能なメモリ番号の範囲がコンピュータのアドレス可能範囲を決定し、その集合をメモリアドレス空間(memory address space)と呼ぶ。32 ビットシステムでは 2^32 byte = 4GB が上限。
変数の本質
C/C++ で変数を定義する構文は簡単。変数を書くとき、実際にはメモリの一部を申請して変数を格納している。int は 4 バイト占有する。
バイトの並び順には大端法(big endian)と小端法(little endian)がある。高位バイトを低アドレスに置くのが大端法、その逆が小端法。PC と Mac は通常小端法、ネットワーク(TCP/IP)は大端法。
メモリ領域
プログラム実行時、コード、データなどは異なるメモリ領域に格納される:コード領域、グローバル/静的領域、スタック、ヒープ、定数領域。
コード領域
.text セグメント。プログラムのバイナリコードを格納、読み取り専用。
グローバル/静的領域
グローバル変数と静的変数を格納。プログラムのライフサイクル中ほぼグローバルに存在。
static キーワード
- 関数内:static 変数はプログラム全体のライフサイクルで値を保持。
- クラス内(変数):static メンバ変数は共有され、全オブジェクトがアクセス可能。クラス外で定義・初期化が必要。シングルトンパターンに適する。
- クラス内(メソッド):static メンバ関数はオブジェクトなしで呼び出し可能。static 変数のみアクセス可能。
スタック
関数呼び出し時の局所変数、引数、戻りアドレスを格納。関数終了後、自動解放。
ヒープ
動的メモリ割り当ての領域。C++ の new(C の malloc)で割り当てたメモリはヒープに。手動で解放が必要。さもなければメモリリークの原因となる。
定数領域
文字列リテラルやコンパイル時定数は定数領域に存在、通常読み取り専用。
メモリ管理
動的メモリ割り当て
動的メモリ割り当て器(Dynamic Memory Allocator)はプロセスの仮想メモリ領域(ヒープ)を管理。割り当てられたブロックと空きブロックを維持。解放は C の free、C++ の delete で明示的に行う。
メモリフラグメンテーション
空きブロックの合計は要求に応えられるが、物理的に複数の小ブロックに分散しているため、十分な連続メモリを確保できない場合がある。これを外部フラグメンテーションと呼ぶ。内部フラグメンテーションは、割り当てブロックが有効ペイロードより大きい場合。
空きリスト
空きリストは割り当て器が空きブロックを検索・使用するためのデータ構造。暗黙的空きリスト、明示的空きリスト、分離空きリストなどの実装方法がある。
参考文献:
- 编程指北(csguide):https://csguide.cn/cpp/memory/what_is_memory.html
- C++ Primer Plus.
