C#での型の扱い方。
こんにちは。みなみんです。
本記事はC#入門シリーズです。
今回は、変数の型について記事にしました。
目次
型について
変数や戻り値には型が存在する。
基本的には同じ型の変数同士でしか代入・参照はできない。
間違ったコードのサンプルを見てもらいたい。(Gist)
「これは明らかにエラーやろ」とつっこまれる。
もう一つ、間違っているであろうサンプルを紹介する。(Gist)
どちらの変数も型は異なるにも関わらず、
不思議と実行できてしまうんですね。
これには理由があるのです。
それは、変数の代入時に「暗黙的型変換」が行われているからです。
暗黙的型変換
変数の代入時にその変数の型と代入しようとしている値の型が異なる場合、自動的(暗黙的)に型の変換が行われます。
これを、「暗黙的型変換」と呼ぶ。(「暗黙的な型変換」とも呼ぶ。)
ただし、暗黙的型変換が行われるには一定の条件があります。
- 数値系の型である事。
- 代入される変数の型が代入する値の型より、サイズの大きい型である事。
- 代入する値の型が符号表記の型である場合、代入される変数の型も符号表記の型である事。
それらの条件を満たさない場合、暗黙的型変換は行われずエラーとなります。
型のサイズ
それぞれの変数の型には決まったサイズがあります。
段ボールにも色んな規格のサイズがあるのと同じですね。
数字には大きく分けて2種類ありますよね。(10進数を基準)
- 整数
- 小数
しかし、同じ種類でも整数型には8種類、小数型には3種類存在するとされています。
変数のサイズはビットの数によって決まります。ビットとは2進数において、表す事の出来る桁数の事です。
例えば、符合付き8bit整数の「8bit」とは、2進数表記で8桁まで表す事ができると言う事です。また、2進数で表せる数(通り数)が数字の最大値となります。2進数において一桁あたり、表すことができるのは2通り。
そして、全体のサイズとして8桁あるので、
2^8 = 256通り
また、符号付き整数という事で、負の整数も表現されるので、範囲は
256 / 2 = 128通り → -128 ~ +128
さらに、0も含み、0に符号は無いので、正の整数の最大値は一つ減る。
-128 ~ +(128-1) → -128 ~ +127
結果から「符号付き8bit整数型」が表す事のできる範囲は「-128~127」である。
よって、変数のサイズはビット数で決まるって事なんですね。
そして、ビットごとの整数型の種類は以下のとおりです。
(サイズが小さい順)
・sbyte型
「符号付き8bit整数型」-128 ~ 127
・byte型
「符号なし8bit整数」0 ~ 255
・short型
「符号付き16bit整数型」-32768 ~ 32767
・ushort型
「符号なし16ビット整数型」0 ~ 65535
(ushortのuは「unsigned:符号がない」から来ている)
・int型(よく見る型)
「符号付き32bit整数型」 -2147483648 ~ 2147483647
・uint型
「符号なし32bit整数型」 0 ~ 4294967295
・long型(符号付き整数では一番サイズが大きい)
「符号付き64bit整数型」-9223372036854775808 ~ 9223372036854775807
・ulong型(符号なし整数では一番サイズが大きい)
「符号なし64bit整数型」0 ~ 18446744073709551615
一方で、小数は「浮動小数点数値型」とも呼ばれる。
やはり、これにもサイズは決まっています。
だが、整数のように単純な物ではないですね。
公式には以下のように範囲が定められています。
[備考]
1byte = 8 bit
ビット数が増えるにつれて小数の桁数も上がって、表現の幅が広がるんですね。
本題に戻って、暗黙的型変換のサンプルを見てもらいましょう。(Gist)
要するに、収納していた箱から値を取り出し、新たに入れようとしている箱の大きさがもともとの箱の大きさより小さかったら入らないのと同じ事です。
また、箱に入らないとその中身が失われてしまうかも知れないですからね。
変数でも同じことで、変換する事でデータが欠損したり失われたりする可能性がある場合は暗黙的変換は行いません。そして、エラーになるんですね。
元の変数型のサイズ(範囲)よりも大きければ型変換ができると。
また、符号がついている型についても新しい型に符号を格納するスペースがなければ変換はできないという事です。
❌ int(符号付き整数) → ulong(より大きいサイズの符号なし整数)
型に符号が付いてるのなら、符号のついた型より大きい型を選びましょう。
暗黙的型変換が出来ない型は何とか変換する方法はないのだろうか。
型を意図的に変換させる処理を組めば良いのです。
意図的に型変換させる事を「明示的型変換」(明示的な型変換)と呼ぶ。
明示的型変換
暗黙的型変換に頼るのも手ですが、コードの量が膨大になってくると変数の型の把握がしにくいものになってしまいます。
また、予期せぬ値になってしまい、バグの原因になりかねません。
それらを防ぐには自分で意図的に型変換を行う「明示的型変換」を行いましょう。
また、「暗黙的型変換」が不可な型変換も明示的型変換で行います。
明示的型変換
明示的型変換を行うには、以下のように書きます。
(変換後の型)変換したい変数
変数名の前に(型)を付加するだけです。
ちなみに、これは「キャスト」とも呼びます。
サンプルをご覧ください。(Gist)
変換する変数の型より小さいサイズの型に変換する場合、代入される値はその型の最大値で割った余り(剰余演算)が代入される。
変換する変数の値 % (変換後の型の最大値 + 1)
(変換後の型の最大値 +1)というのは、そのまま最大値で剰余を求めてしまうと、最大値 = 0となって、最大値が変わってしまうため、+1している。
また、変換する型が小数点を含む型で整数型に変換する場合、変換時に小数点以下は切り捨てられます。(小数点以下を削除する)
文字列から数値に変換する
ここまでは、数値系の変換を扱ってきた。
文字列(string等)での「"123"」は数字に見えるが、型としては「文字列型」として扱われる。
数字の「文字列」が格納されたstring型の変数が二つあるとしよう。
string X = "10";
string Y = "5";
(見た目的に)数字だからといって、そのまま
string Answer = X + Y;
としてしまうと、間抜けな事が起こる。(中身は15を期待している)
Console.WriteLine(Answer);
//>> 105
こういう現象が起きる。
これは、あくまでも「文字列」型なので、文字列同士による足し算(=文字の結合)が行われたと言う事である。
数値として演算させるのなら、型変換を行う必要があると。
文字列から数値
まずはサンプルを見てもらおう。(Gist)
確かに、最初の所の答えを入れる変数の型選びのセンスもダメだったのは申し訳ない。
float型の変数Ansに代入する時、文字列からfloat型に変換を行なっている。
変換は型クラスの関数によって行う。ここではfloat型。
float.Parse(変換したい文字列型変数)
int型でもほぼ同じく、
int.Parse(変換したい文字列型変数)
次回はC#でのクラス定義
この記事に誤りがあるかもしれません。その辺はご了承ください。
本記事で紹介されている方法・手法はあくまでも個人的なものです。