LoginSignup
7
5

More than 5 years have passed since last update.

C#のデータ型を説明してみた

Last updated at Posted at 2019-04-08

 この文章はC#入門者が半ば自分のメモ書きのように書いたものです。おそらく間違いは多々あるとは思いますが、温かく見守ってください。本の内容を自分なりに解釈して、また実験を行っての「当時の理解」が記事に反映されています。
 また、プログラム内部の変数名などに全大文字のローマ字書きが使われています、お気をつけください。逆に全大文字の部分は自由に変更しても大丈夫な部分です。


C#で扱うデータに関しての基礎のメモ書き

数字データに関して

・C#では、変数の型と変数の名前を宣言して定義する。

 例えば下記のような形。

sample
int HENSU = 10;
const int TEISU = 10;

 ここで使用したconstは宣言した変数を定数とする修飾子で、宣言時に代入した数値を保持し続けるように変えるものである。これ以後、constで宣言された数値は定数となり、定数に再代入を行うプログラムはエラーを返すようになる。

 また、定数を作る際には初期値を与える必要がある。変数のように枠だけ作っておく、という事は出来ない。

 変数には様々な型があり、それぞれ使える範囲が決まっている。例えばbyteであれば0~2 8-1までの正の整数、intであれば±(231-1)までの整数、小数点以下を扱う際にはfloatdoubledecimalという型もある。

 ここで、最大値に-1が付いている理由は数字の初めが0だからである。8ビットで表すことのできるパターンは256通りで、そのうち一つを0に割り当てる必要があるためにそうなっている。

 sbyteと書けばbyteと同じデータサイズで符号をつけることができたり(つまり範囲は-27~27-1)、uintと書けばintと同じデータサイズで正の数のみのデータ(つまり範囲は0~232-1)になったりする。
 これは整数を扱う型に限られ、sを付けるかuを付けるかは元の型に符号が付いているか否かで判別する。

 以下に数字を扱う型の一覧を示す。


整数を扱う型

型の名前 サイズ(bit) 範囲 規定値
byte 8 0 ~ 255 0
short 16 -32768~32767 0
int 32 -2,147,483,648~2,147,483,647 0
long 64 -9,223,372,036,854,775,808~9,223,372,036,854,775,807 0L

小数点以下も扱える型

型の名前 サイズ(bit) 規定値
float 32 0.0F
double 64 0.0D
decimal 128 0.0M

*範囲は小数点の位置によって変動する。
double型よりもdecimal型のほうが数値精度が高いが、数値範囲はfloat型よりもdecimal型のほうが小さい。また、CPUによってはdecimal型そのものがサポートされていないことがあり、計算速度が圧倒的に遅くなることがあるようだ。


数字データの格納/代入に関して

 作成したbyteデータをbyte型よりデータサイズの大きいint型に格納することは可能であるが、その逆は不可能である。ただし、とある宣言を行うことで強引に変換することもできる。

キャスト
//代入元データ
byte MOTO_BYTE = 100;
int MOTO_INT = 200;

byte SAKI_A = MOTO_BYTE;//可能
byte SAKI_B = MOTO_INT;//不可能
byte SAKI_C = (byte)MOTO_INT;//可能

 byte e = (byte)b;の行で、(byte)と代入する側に付記している。これによりint型の数値をbyte型に変換しているため、この式の内部ではbyte型にbyte型を代入していることになっていて、エラーとならない。ただし、この手法には問題もあり、例えば下のようなプログラムは正しい値を返すことはない。

キャストエラー
int MOTO = 500;
byte SAKI_A = (byte)a;//bの値は244
byte SAKI_B = (byte)(a*-1);//cの値は12
byte CHOKUSETU = 500;//これはエラーとなる

 これはビットで計算した際にint型で格納されているデータの9ビット以上の値がbyte型に変換される際に切り捨てられる(厳密に演算したとしても下8ビットに影響を及ぼさない)ことに原因がある。これによって256を表す9ビット目が切り捨てられ、244という値になっている。

 cの値が244とならないのは二進数における負の数の表し方に原因があり、00000...000と32個0が連なったintにおける規定値0のデータを負の方向にオーバーフローさせた11111...111を-1としていて、-2,-3と値が下がっていくごとに2進数を繰り下げていく方式であるために、負の数の下8ビットだけを参照した際に、8ビットすべてが1の値、つまり256から244を引いた値で12となっている。

 500を直接byte型に代入しようとするとエラーとなる。オーバーフロー/アンダーフローが起きるのはあくまでも変数から変数への代入を強引に(型変換を用いて)行った場合だけである。
 ちなみに500をsbyte型に代入した場合は-12となり、-500を代入した場合は12となる。なんとなく不思議な気分だ。

その他のデータに関して

 C#で数字以外のデータを扱う型で簡単に触れられると私が思うのはbool型、char型、string型の三種である。
 以下でそれぞれの型についてまとめる。


bool(論理型)

 trueまたはfalseの二値を格納する型。比較演算子を用いた演算結果の格納にも用いることが出来る。よくフラグ管理に使う。
 外部からの代入はtrueまたはfalseを受け付ける。条件式が真か偽かという結果もここで保持することができる。
 データサイズは8bit。


char(文字型)

 文字を一つだけ格納する型。手動で格納する際には`(シングルクォーテーション)で文字を囲んで格納する。個人的に使用したのはデータ転送で一文字づつ送られてくるものを保存するときのみ。もしかすると後述のstring型で代用できるかもしれない。\u〇〇〇〇という形で直接文字コードで生成することも出来る。(には16進数が入る)
 データサイズは16bit。


string(文字列型)

 文字列を格納する型。手動で格納する際には\"(ダブルクォーテーション)で文字を囲んで格納する。シングルクォーテーション二回ではない。最初は騙された。数値を扱う方を含む、以上に示した型のどれとも違い、変数の中に直接格納するものではなくどこかにあるデータのアドレスを格納する型である。その二種に関してはいずれ触れるかもしれない。
 データサイズは前後し、最大で2GBとのこと。

The maximum size of a String object in memory is 2GB, or about 1 billion characters.
Stringオブジェクトの最大メモリは2GB、またはおよそ十億文字。

https://docs.microsoft.com/ja-jp/dotnet/api/system.string :stringクラス解説の注釈欄より抜粋


ユーザーが中身を定義する型に関して

 c#には最初から用意されている前述の10(+α)種類のデータ形式だけでなく、ユーザーが形式を定義出来る型が用意されている。
 その型とは列挙型配列構造体の三つである。

列挙型に関して

 enum 名前:型名(整数型に限る){ 中身1,中身2, ... ,中身N };のような形で宣言できる型。:型名の部分は省略でき、省略した場合は自動的に中身はint型になる。中身に対して何も代入しないと、中身1,中身2,...には0から順に番号が代入されていく。N番目の中身にはN-1番が代入される。途中の中身にも番号を代入することが出来る。代入した中身の後ろには、そのまま順番に番号が代入される。
 また、中身に格納した数字を取り出すには型宣言が必要になる。

enum
enum REKKYO:byte{
    NAKAMI1,NAKAMI2 = 10,
    NAKAMI3
}
System.Console.WriteLine(REKKYO.NAKAMI3);//出力:NAKAMI3
System.Console.WriteLine((byte)NAMAE.NAKAMI3);//出力:11

配列型に関して

array
//bool以外の型であればよい
int[] HAIRETU;
HAIRETU = new int[3];
/***/
int[] HAIRETU2 = new int[3];
/***/
int[] HAIRETU3 = new int[3] {0,1,2}

 上記/***/で区切られた文章それぞれが別の配列型を宣言する方法である。上から順に私の思う使い道を述べていく。

  1. とりあえず配列の名前だけ作っておいて、分岐先で大きさを分けることが出来る。条件によって要素数が変わるときに使える。
  2. とりあえず空配列ができる。後から要素を埋めるが、その要素が決まっていない際に使える。
  3. 要素の決まった配列が作れる。暫定的、もしくは変動しない要素を作るときに使える。(ReadOnlyと併用するとよい?)

構造体に関して

stract
public struct KOZOTAI{
    public int SUUJI;
    public string MOJI;
}

 こいつに関してはよくわかってない。多分classを作るときのようなことをすると思われる。万が一これを目当てにしてきた人にはごめんなさい。ここまでの間違いまくりのどや顔解説も出来ないくらいわかってない。なんだこれは。

 まず、Main()の外で上記コードみたいな感じで関数を作る。そのあと、Main()の中でKOZOTAI型の変数?を宣言することで空のKOZOTAI型を作ることが出来る。ここではKOZOTAI型変数?の名称をSHISAKUとする。

struct2
KOZOTAI SHISAKU; //これで空っぽのKOZOTAI型ができる。初期化は出来ない。初期化にはまた別の関数を作る必要があるらしい。
string TEST;    //こちらは比較用。なんとなく似た形になっているのがわかる。

 KOZOTAI型の変数SHISAKUSHISAKU.SUUJISHISAKU.MOJIからなっていて、それぞれ多分既定値が入っている。ここから、SHISAKU.SUUJISHISAKU.MOJIを編集することが出来る。

struct3
SHISAKU.SUUJI = 100;
SHISAKU.MOJI = "文字";//ここではstring型やint型の編集ルールをそのまま用いる。

 以上で、SHISAKU.SUUJISHISAKU.MOJIの二つの要素を持つ構造体のSHISAKUが完成した。なんだこれは。
 

*追記
 大体classと似たようなことができるらしい。classよりだいぶ軽いけどその分制約(初期化はダメ、継承不可等)が多いらしい。あとclassは参照型だけど構造体、structは値型だとか。以下のサイトで長野 透様がわかりやすく解説してくださっていました。

https://www.sejuku.net/blog/59663 『【C#】構造体の使い方(クラスとの違い、初期化や配列の使用も解説)』

7
5
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5