今更ながら,変数の型について
皆さんがこれまで扱ってきた変数の型は,大雑把に,整数型,文字列(配列),浮動小数点型で
覚えていると思います.
分類 | 型 | データの大きさ | 具体的な値の範囲 | 備考 |
文字型 | char | 1byte=4bit | -128 〜 127 | ASCII文字に対応(英文字,数字,記号) |
整数型 | short int | 2byte=8bit | -32768 〜 32767 | 短整数 |
int | 2byte=8bit または 4byte=16bit |
-32768 〜 32767 または -2147483648 〜 2147483647 |
処理系によって大きさが変わる 通常は長整数 |
|
long int | 4byte=16bit | -2147483648 〜 2147483647 | 長整数 | |
浮動小数点型 (実数型) |
float | 4byte=16bit | 最小の正の数1.175494351e-38 最大の正の数3.402823466e+38 |
単精度 |
double | 8byte=32bit | 最小の正の数2.2250738585072014e-308 最大の正の数1.7976931348623158e+308 |
倍精度 | |
long double | 8byte=32bit | 最小の正の数2.2250738585072014e-308 最大の正の数1.7976931348623158e+308 と同等またはそれ以上の精度 |
拡張精度 処理系によって精度が変わる |
|
符号なし文字型 | unsigned char | 1byte=4bit | 0 〜 255 | ASCII文字に対応(英文字,数字,記号) |
符号なし整数型 (実数型) |
unsigned short int | 2byte=8bit | 0 〜 65535 | 符号なし短整数 |
unsigned int | 2byte=8bit または 4byte=16bit |
0 〜 65535 または 0 〜 4294967295 |
処理系によって大きさが変わる 通常は長整数 |
|
unsigned long int | 4byte=16bit | 0 〜 4294967295 | 符号なし長整数 |
上記の表を見るといくつが疑問がわいてくると思われます.
int, unsigned int, long doubleはいったいどのような大きさになるのでしょうか?
約束事としては,
short int ≦ int ≦ long int, float ≦ double
≦ long double
となっているので,intはどちらか分からず,long
doubleもはっきりしなくなってしまうのです.
Windows系では,仕様で,int = long int, double
= long doubleとなっていますが,必ずこの
通りではないシステムがあることも知っておきましょう.
文字型になぜunsignedがあるのはなぜでしょうか?
元々は英文字,数字,記号だけのASCII文字に対応していたので,7bit分で収まっていたため,
先頭の符号はどちらでも問題なかったため,符号付きでも符号なしでもよかったというのがあり
ます.ASCII文字以外を使う場合もあり,英語以外の文字は2バイト文字と呼ばれ2バイトで文字を
表現する必要があるため,厳密にはunsigned
charとし,文字でなく,文字列として扱うことが必要
となります.
さらに説明を加えると,文字型と言っても整数型のひとつに過ぎないのです.中身は番号ですので
文字そのものの意味はありません.さらにいえば,char
= 200と小さな値の整数値を代入することも
できるのですが,上記の範囲からunsigned char
= 200 にしないと範囲を超えてしまいます.
授業で積極的に使うことはありませんが,1バイトで示せる整数値という意味もあるのです.
数値の範囲のほか有効桁数を知っておく必要があります.math.hで用意されているような数学演算の
関数の戻り値などは総じてdoubleで返ってきますので,以下のような桁を考慮しておいて下さい.
float | 切り捨て5桁〜四捨五入6桁 |
double | 切り捨て15〜四捨五入16桁 |
キャストと文字列変換関数
型の異なる変数を用いて演算を行う場合,暗黙の了解による型変換が行われて計算されますが,
演算の順番に依存することに注意しなければなりません.
double型の結果が欲しいのにint型が混ざっていたために,小数点以下が切り捨てられながらも,
結果はdouble型となって得られるような問題が発生します.
従って整数型で宣言された変数をdouble型の演算で用いる場合,(int)などを付すことにより,型を
明示的に変換することができます.これをキャストと呼んでいます.
あるいは,stdlib.hに用意されている以下のような関数を用いて,文字列として得た数値を必要な型に
変換することもあります.文字列は変数ではなく,配列ですので単なるキャストはできません.
atoi 関数: 文字列からint型に変換
atol 関数: 文字列からlong int型に変換
atof 関数: 文字列からdouble型に変換
strtol 関数: 文字列からlong int型に変換(変換エラーを返す機能あり)
strtoul 関数: 文字列からunsigned long
int型に変換(変換エラーを返す機能あり)
strtod 関数: 文字列からdouble型に変換(変換エラーを返す機能あり)
コンパイルエラーが出ない大きな問題
型については時折厄介な問題を引き起こします.おなじみの関数scanfを例に取りましょう.
引数には変数がありますが,数値を獲得するときに%記号で型を指定します.
%記号の種類
種類 | 表記例 | 説明 |
%d | %d | int型, short型変数を10進数で表示 |
%%4d | int型, short型変数を10進数で表示 符号を含んで全体を4桁で表示 |
|
%ld | %ld | long型変数を10進数で表示 |
%f | %f | float型変数を10進数で表示 |
%6.3f | float型変数を10進数で表示 全体の桁数は6桁、小数点以下は3桁で表示 |
|
%lf | %lf | double型変数を10進数で表示 |
%16.12lf | double型変数を10進数で表示 全体の桁数は16桁、小数点以下は12桁で表示 |
|
%c | %c | char型変数に記憶されている数値に対応したASCIIコードにより文字(1文字)を表示 |
%s | %s | char型配列変数に記憶されている文字列を表示 文字列の終端はNULL文字(数値の零)で示す 配列のどれかにNULL文字がなければならない |
型が一致していなければならないのですが,上記のように型の大きさによっては都合よく(あやふやに)
変換されてしまうため,コンパイルエラーが出ないという問題があるのです.
実行時には型が合っていないため,エラーが発生します.
例えばですが,doubleで宣言しておいた変数に対し,%fを使ったとします.コンパイルはそれとなくできて
しまうのですが,float型で獲得したものをdouble型にするため不整合が発生します.
scanf関数はポインタとして数値を獲得するため,型の変換など行われず,直接上記のようなやり取りが
あるために起こる問題と言えます.