型とメモリ
メモリの内部構造
変数の値は全てメモリ上に格納されます。Int32型の変数の値がどのように格納されるかを説明し変数のメモリについて理解を深めます。 まずはメモリがどのように動作するかを説明します。
メモリの内部にはオンかオフかを記憶する1ビットの記憶素子(メモリセル)が格子状に配置されています。 メモリセルにはメモリアドレスが割り振られており、このメモリアドレスによってどの記憶素子の値を書き換えるか指定できます。
数字がメモリアドレスで灰色のセルにはオフという値が入っており黄色のセルにはオンという値が入っているとします。 メモリの値を書き換えるには例えば以下のようなコードを書く必要があります。
※注)このコードは概念コードで実際にこういうプログラム言語があるわけではありません
mem_alloc(3, on); //メモリアドレスが3の場所の値をオンにする
mem_alloc(7, off); //メモリアドレスが3の場所の値をオフにする
そうすると上記のメモリの状態がこのように変わります。
メモリはデータの読み書きが非常に高速です。ハードディスクは物理的なシーク処理が走るのに対し、メモリは電気操作で動くからです。 しかしメモリはパソコンの電源を切るとデータが全てなくなります。記憶しておきたいデータはハードディスクなどの外部記憶装置に保存したほうがいいでしょう。
数値型とメモリ
数値をメモリで表現する
メモリには電気のオンとオフを記憶することができるメモリセルが大量に並んでいるということは上記で説明しました。 これによって例えばオンを1、オフを0と定義すれば数字の0と1を記憶させることができます。しかしながら0と1しか記憶できない のではあまり役に立ちません。少し考えるとメモリセルが2つあると0から3までの4つの数を記憶させることができます。
メモリセルが3個あると0から7までの8個の数を表現できます。
一般化するとメモリセルがN個あると2^N乗の数の数値を表現できます。 例えばメモリセルが8個あると2×2×2×2×2×2×2×2=256個の数値を表せます。 各メモリアドレスの値と数値の値には法則があります。
左から1、2、4、8、…と2^N乗の数字を振り、オンになっている部分の数を足し合わせると表現している数値の値になります。
型はなぜあるのか?
C#で以下のように変数を宣言した場合を考えて見ましょう。
Byte x = 100;
Byte型の変数を宣言すると8bit、つまりメモリセルが8個分確保されます。この8個のメモリセルを使ってxの値を格納します。
4+32+64=100です。プログラマがメモリセルのオンオフで値を管理しなければならないとすると非常に大変です。 例えば以下のようなコードを書いてメモリに値を格納しなければなりません。
mem_alloc(2, on); //メモリアドレスが0の場所の値をオンにする
mem_alloc(5, on); //メモリアドレスが5の場所の値をオンにする
mem_alloc(6, on); //メモリアドレスが6の場所の値をオンにする
型を使用することで数値を表すということを簡単に実現でき、プログラムを書くのが容易になるのがわかります。
型という概念を導入することでメモリがどう使われているかを意識せずに値の読み書きができるのが大きなメリットです。
Byteよりも大きい数字を表すための型もあります。UInt16は16個、UInt32は32個、UInt64は64個のメモリセルを使用します。
同様にSByteは8個、Int16は16個、Int32は32個、Int64は64個のメモリセルを使用します。SByteはSigned Byteの略です。 SByteやInt16などは符号付整数で正の数と負の数を表せます。例えばSByteは-128から127までの表すことが可能です。
SByte x = -28;
メモリは以下のようになっています。
SByteの場合オンのセルを足し合わせた数から128を引きます。 この128という数字は何によって決まるかというとSByteが表現可能な数の個数256を2で割ったものです。 SByteが表現可能な数は2^8乗で256個になります。Int16、Int32、Int64も同様のルールで数値の値が決まります。
文字型とメモリ
数値を表すのと同様の方法で文字を表すことが可能です。数字の変わりに文字を割り当てることでメモリのオンオフで文字を表現できます。 このオンオフと文字とのマッピングのルールのことを文字コードといいます。下に示すコードを実行すると変数cにはdという文字が入ります。 これは100という数字がdという文字にマッピングされているためです。
Char c = (Char)100;
例えば以下のコードを用いて33から126までの数字を文字に変換した結果は以下のようになります。
String s = "";
for (int i = 33; i < 127; i++)
{
    s += String.Format("{0} = {1}", i, (Char)i) + Environment.NewLine;
}
//sに「数字=文字」の文字列が入っています
33 = !
34 = "
35 = #
36 = $
37 = %
38 = &
39 = '
40 = (
41 = )
42 = *
43 = +
44 = ,
45 = -
46 = .
47 = /
48 = 0
49 = 1
50 = 2
51 = 3
52 = 4
53 = 5
54 = 6
55 = 7
56 = 8
57 = 9
58 = :
59 = ;
60 = <
61 = =
62 = >
63 = ?
64 = @
65 = A
66 = B
67 = C
68 = D
69 = E
70 = F
71 = G
72 = H
73 = I
74 = J
75 = K
76 = L
77 = M
78 = N
79 = O
80 = P
81 = Q
82 = R
83 = S
84 = T
85 = U
86 = V
87 = W
88 = X
89 = Y
90 = Z
91 = [
92 = \
93 = ]
94 = ^
95 = _
96 = `
97 = a
98 = b
99 = c
100 = d
101 = e
102 = f
103 = g
104 = h
105 = i
106 = j
107 = k
108 = l
109 = m
110 = n
111 = o
112 = p
113 = q
114 = r
115 = s
116 = t
117 = u
118 = v
119 = w
120 = x
121 = y
122 = z
123 = {
124 = |
125 = }
126 = ~
文字のデータをハードディスクに保存したり違うマシンに文字データを送ったりする際には一度文字データを数値のデータに置き換えないと いけません。コンピューターはオンオフのデータしか扱えないため数値データはさらにオンとオフのデータに変換された上で送られます。 文字を数値に変換する処理のことをエンコード、反対の処理をデコードと言います。
エンコードとデコードで使う文字コードが合っていないと文字化けが起こります。
C#ではEncodingクラスにエンコード処理の機能がまとめられています。
System.Text.Encoding en = System.Text.Encoding.UTF8;
String myText = en.GetString(new Byte[] { 100 }); //myTextにはdが入っています
ファイルに保存する時にもエンコーディングを指定することが可能です。
System.Text.Encoding en = System.Text.Encoding.UTF8;
System.IO.File.WriteAllText("C:\MyMemo.txt", "メモの内容", en);
Create at 2012/1/9 LastUpdate 2012/1/17