C言語の基本データ型と派生データ型について解説します。
C言語におけるcharは、8ビットの符号付き整数を表すデータ型である。とはいえ、数値を格納するために用いられることは少なく、文字を格納するために使われることが多い。
[signed|unsigned] char
signed 及び unsigned を省略した場合は、原則として符号付き (signed) となる。ただし、コンパイラのオプションを指定することにより、char のデフォルトを符号無し (unsigned) にすることもできる。
gcc の場合、-funsigned-char オプションを指定すると、singed 及び unsigned で修飾されていない char を unsiged char として解釈する。-fsigned-char オプションを指定すると、singed 及び unsigned で修飾されていない char を signed char として解釈する。
C言語の符号付き整数では、負(マイナス)の数を2の補数で表す。
2進数 | 10進数 | 備考 |
---|---|---|
00000000 | 0 | |
01111111 | 127 | 最大値 |
10000000 | -128 | 最小値 |
11111111 | -1 |
8ビットの符号付き整数を使用する例を以下に示す。
char add(char x, char y) {
char sum;
sum = x + y;
return sum;
}
char のサイズは 8 ビットであり、limits.h で CHAR_WIDTH として定義されている。sizeof(char) でサイズを求めることもできる。
char の最小値は、limits.h で CHAR_MIN として定義されている。char のデフォルトが符号付き (signed) か符号無し (unsigned) かによって値が異なる。
char の最大値は、limits.h で CHAR_MAX として定義されている。char のデフォルトが符号付き (signed) か符号無し (unsigned) かによって値が異なる。
C言語における signed char は、8 ビットの符号付き整数を表すデータ型である。
signed char のサイズは 8 ビットであり、limits.h で SCHAR_WIDTH として定義されている。sizeof(signed char) でサイズを求めることもできる。
signed char の最小値は -128 (0b10000000) であり、limits.h で SCHAR_MIN として定義されている。
signed char の最大値は 127 (0b01111111) であり、limits.h で SCHAR_MAX として定義されている。
C言語における unsigned char は、8 ビットの符号無し整数を表すデータ型である。
unsigned char のサイズは 8 ビットであり、limits.h で UCHAR_WIDTH として定義されている。sizeof(unsigned char) でサイズを求めることもできる。
unsigned char の最小値は 0 (0b00000000) である。符号無し整数の最小値は常に 0 であるため、limits.h では定義されていない。
unsigned char の最大値は 255 (0b11111111) であり、limits.h で UCHAR_MAX として定義されている。
shortは16ビットの符号付き整数を格納するためのデータ型である。
[signed] short [int]
2進数 | 10進数 | 備考 |
---|---|---|
0000000000000000 | 0 | |
0111111111111111 | 32767 | 最大値 |
1000000000000000 | -32768 | 最小値 |
1111111111111111 | -1 |
16ビットCPUが主流だった時代にはよく使われていたが、現在はあまり使われないデータ型である。
short intと記述することもできる。
short int m;
short n = 1024;
C言語における unsigned short は、16 ビットの符号無し整数を表すデータ型である。
signed short のサイズは 16 ビットである。sizeof(signed short) でサイズを求めることもできる。
signed short の最小値は -32,768 (0b1000000000000000) であり、limits.h で SHRT_MIN として定義されている。
signed short の最大値は 32,767 (0b0111111111111111) であり、limits.h で SHRT_MAX として定義されている。
C言語における unsigned short は、16 ビットの符号無し整数を表すデータ型である。
unsigned short のサイズは 16 ビットである。sizeof(unsigned short) でサイズを求めることもできる。
unsigned short の最小値は 0 (0b0000000000000000) である。符号無し整数の最小値は常に 0 であるため、limits.h では定義されていない。
unsigned short の最大値は 65,535 (0b1111111111111111) であり、limits.h で USHRT_MAX として定義されている。
16ビットまたは32ビット符号付き整数型
[signed] int
int x;
signed int y = -1;
unsigned int z = 1;
int型で表せる最小値および最大値は処理系によって異なる。
limits.h で int 型のサイズ、最小値及び最大値が定義されていることがある。limits.h の例を以下に示す。
#define INT_MIN (-INT_MAX - 1)
#define INT_MAX 2147483647
#define UINT_MAX 4294967295U
#define INT_WIDTH 32
#define UINT_WIDTH 32
int のサイズは 16 ビット又は 32 ビットであり、limits.h で INT_WIDTH として定義されている。sizeof(int) でサイズを求めることができる。
C言語における unsigned int は、16 ビット又は 32 ビットの符号無し整数を表すデータ型である。
signed int のサイズは 16 ビット又は 32 ビットである。sizeof(signed int) でサイズを求めることができる。
signed int の最小値は -32,768 又は -2,147,483,648であり、limits.h で INT_MIN として定義されている。
signed int の最大値は 32,767 又は 2,147,483,647 であり、limits.h で INT_MAX として定義されている。
C言語における unsigned int は、16 ビット又は 32 ビットの符号無し整数を表すデータ型である。
unsigned int のサイズは 16 ビット又は 32 ビットである。sizeof(unsigned int) でサイズを求めることもできる。
unsigned int の最小値は 0 である。符号無し整数の最小値は常に 0 であるため、limits.h では定義されていない。
unsigned int の最大値は 65,535 又は 2,147,483,647 であり、limits.h で UINT_MAX として定義されている。
32ビットまたは64ビット符号付き整数型
[signed] long [int]
long x;
signed long y = -1L;
unsigned long z = 1L;
long型で表せる最小値および最大値は処理系によって異なる。
long のサイズは 32 ビット又は 64 ビットであり、limits.h で LONG_WIDTH として定義されている。sizeof(long) でサイズを求めることができる。
C言語における unsigned long は、32ビットまたは64ビットの符号付き整数を表すデータ型である。
signed long のサイズは 32 ビット又は 64 ビットである。sizeof(signed long) でサイズを求めることができる。
signed long の最小値は -2,147,483,648 又は -9,223,372,036,854,775,808 であり、limits.h で LONG_MIN として定義されている。
signed long の最大値は 2,147,483,647 又は 9,223,372,036,854,775,807 であり、limits.h で LONG_MAX として定義されている。
C言語における unsigned long は、32ビットまたは64ビットの符号無し整数を表すデータ型である。
unsigned long型で表せる最大値は処理系によって異なる。limits.h の ULONG_MAX マクロで最大値が定義されている。
unsigned long のサイズは 32 ビット又は 64 ビットである。sizeof(unsigned long) でサイズを求めることができる。
unsigned long の最小値は 0 である。符号無し整数の最小値は常に 0 であるため、limits.h では定義されていない。
unsigned long の最大値は 4,294,967,295 又は 18,446,744,073,709,551,615 であり、limits.h で ULONG_MAX として定義されている。
long longは、64ビットの符号付き整数を表すデータ型である。
long long のサイズは 64 ビットであり、limits.h で LLONG_WIDTH として定義されている。sizeof(long long) でサイズを求めることもできる。
long long の最小値は -9,223,372,036,854,775,808 であり、limits.h で LLONG_MIN として定義されている。
long long の最大値は 9,223,372,036,854,775,807 であり、limits.h で LLONG_MAX として定義されている。
signed long longは、64ビットの符号付き整数を表すデータ型である。
unsigned long longは、64ビットの符号なし整数を表すデータ型である。
unsigned long long のサイズは 64 ビットである。sizeof(unsigned long long) でサイズを求めることができる。
unsigned long long の最小値は 0 である。符号無し整数の最小値は常に 0 であるため、limits.h では定義されていない。
unsigned long long の最大値は 18,446,744,073,709,551,615 であり、limits.h で ULLONG_MAX として定義されている。
enum は列挙型であり、定数のリストを定義して使う。それぞれの定数には、自動的に整数値が割り当てられる。
列挙型の定義方法を以下に示す。
enum tag { list };
列挙型変数の宣言方法を以下に示す。
enum tag variable;
列挙型の定義とその変数の宣言を一度に行うこともできる。ただし、変数の宣言を伴うため、関数内で行う必要がある。
enum [tag] { list } variable;
列挙型の使用例を以下に示す。
enum ACCOUNT {
SAVING,
CHECKING
};
int main(int argc, char **argv) {
enum ACCOUNT account = SAVING;
account = CHECKING;
}
なお、列挙子に存在しない整数値を列挙型の変数に代入しても、プリコンパイルやコンパイルの際に警告やエラーは発生しない。
元々C言語にはブール型は存在しなかったため、ブール値は int 型等で代用してきたが、現在では bool 型がサポートされている。
bool 型並びにその値である true (1) 及び false (0) を使うためには、stdbool.h をインクルードする必要がある。
#include <stdbool.h>
int main(int argc, char **argv) {
bool flag = false;
flag = true;
}
bool 型の最大値は 1 であり、limits.h で BOOL_MAX として定義されている。
C言語における float は、IEEE 754で規定されている単精度の浮動小数点数を表すデータ型である。
符号部 | 指数部 | 仮数部 |
---|---|---|
1ビット | 8ビット | 23ビット |
符号部は数値の符号を表す。0 の場合は正 (+)、1 の場合は負 (-) である。大小比較をやり易くするため、浮動少数点数では負の数を表すのに 2 の補数を使わない。
指数部は仮数部の値を何ビット左シフトするかを表す。127 から指数部を引いたビット数だけ、仮数部の値を左シフトする。
仮数部は固定小数点の小数点以下の部分を表す。仮数部が 00000000000000000000000 であれば 0b1.0、仮数部が 11100000000000000000000 であれば 0b1.111 を表す。
なお、0 はこのルールで表せないため、全てのビットが 0 である場合に 0 と定義されている。
2進数 | 10進数 | 備考 |
---|---|---|
1 01111111 00000000000000000000000 | -1 | 0b1.0 << 2127-127 |
0 00000000 00000000000000000000000 | 0 | |
0 01111101 00000000000000000000000 | 0.25 | 0b1.0 << 2125-127 |
0 01111110 00000000000000000000000 | 0.5 | 0b1.0 << 2126-127 |
0 01111111 00000000000000000000000 | 1 | 0b1.0 << 2127-127 |
0 10000000 00000000000000000000000 | 2 | 0b1.0 << 2128-127 |
0 10000000 10000000000000000000000 | 3 | 0b1.1 << 2128-127 |
0 10000001 00000000000000000000000 | 4 | 0b1.0 << 2129-127 |
0 10000001 01000000000000000000000 | 5 | 0b1.01 << 2129-127 |
0 10000001 10000000000000000000000 | 6 | 0b1.1 << 2129-127 |
0 10000001 11000000000000000000000 | 7 | 0b1.11 << 2129-127 |
0 10000010 00000000000000000000000 | 8 | 0b1.0 << 2130-127 |
float 型では単精度浮動小数点演算ができます。
float f1, f2, f3;
f1 = f2 + f3;
旧仕様 (K&R) では次のような順番で演算されました。
しかし、ANSI ではすべて単精度で演算されます。
-3.402823e+38
3.402823e+38
C言語における double は、IEEE 754で規定されている倍精度の浮動小数点数を表すデータ型である。
部 | ビット数 |
---|---|
符号部 | 1 bit |
指数部 | 11 bit |
仮数部 | 52 bit |
-1.797693e+308
1.797693e+308
構造体 (struct) とは、複数のフィールドを持つデータ型である。
構造体の定義方法を以下に示す。
struct tag { list };
構造体変数の宣言方法を以下に示す。
struct tag variable;
構造体の定義とその変数の宣言を一度に行うこともできる。ただし、変数の宣言を伴うため、関数内で行う必要がある。
struct tag { list } variable;
構造体の使用例を以下に示す。
struct COODINATES {
double x;
double y;
};
int main(int argc, char **argv) {
struct COODINATES coordinates;
coordinates.x = 1.0;
coordinates.y = 2.5;
}
union (共用体)は、同一のデータ領域を複数の異なるデータ型が共用するようにしたものです。
union タグ名 {
変数宣言のリスト
};
以下の場合には、タグ名を省略することが可能です。
変数宣言のリストの中に共用体を入れて、入れ子構造にすることも可能です。
共用体内の最初のメンバの初期化が可能です。
union x {
char a[4];
int b;
};
union x ux = { 'U', 'N', 'I', 'X' };
voidは引数または戻り値が無いことを表す特殊なデータ型です。たとえば、引数を取らない関数は次のように定義します。
int getchar(void);
戻り値を返さない関数は次のように定義します。
void exit(int status);
void *
は汎用の(型に依存しない)ポインタ型を表します。たとえば、汎用のポインタ型を引数に取る関数は次のように定義します。
void free(void *ptr);
汎用のポインタ型を返す関数は次のように定義します。
void *malloc(size_t size);
汎用型ポインタは型を特定することができないため、ポインタが指し示す値を直接参照することができません。他のポインタ型に変換してから参照します。
void *p;
int *i;
p = malloc(sizeof(int));
*p = 0; /* NG */
i = p;
*i = 0; /* OK */
void **
のようにvoid
型のポインタへのポインタにすることはできません。
基本データ型の他にシステムコールやライブラリ関数で使用される派生データ型があります。 実際は何らかの基本データ型なのですが、移植性を高めるために別の名前が付けられています。
派生データ型はマクロで定義されているため、ヘッダーファイルをインクルードする必要があります。派生データ型によってインクルードするヘッダーファイルの名前は異なりますが、たいていの派生データ型は sys/types.h をインクルードすることで使用できるようになります。
派生データ型には、次のようなものがあります。
システムの時間をクロック刻み (clock tick) で表すデータ型
clock_t clock(void);
デバイス番号に使用されるデータ型
ファイルサイズとオフセット(先頭からの相対位置)用に使用されるデータ型
2つのポインタの減算結果を示す符号付き整数型
メモリー内のオブジェクトのサイズ(バイト単位)用に使用される型
バイト数またはエラーのどちらを返すこともある関数によって使用される符号付きサイズ型
秒単位の時間用に使用される型
time_t time(time_t *tloc);
char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);
struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result);
struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);
ポインタを格納するために十分なサイズの符号付き整数型 (Solaris)
ポインタを格納するために十分なサイズの符号なし整数型 (Solaris)
精度が異なるデータ型の変数へ代入すれば、暗黙的に型変換される。
short a = 1;
int b = a;
型を明示して変換することもできる。これを「キャスト」と呼ぶ。
float f = 1.2;
double d = (double)f;
文字列をint型に変換するには、atoi関数を使う。
#include <stdlib.h>
int example(char *s) {
int i = atoi(s);
return i;
}
文字列をlong型に変換するには、atol関数を使う。
#include <stdlib.h>
long example(char *s) {
long l = atol(s);
return l;
}
文字列をdouble型に変換するには、atof関数を使う。
※float型ではないことに注意
#include <stdlib.h>
double example(char *s) {
double d = atof(s);
return d;
}
文字列をlong型の数値に変換する。
#include <stdlib.h>
long int strtol(const char *nptr, char **endptr, int base);
文字列をlong long型の数値に変換する。
#include <stdlib.h>
long long int strtoll(const char *nptr, char **endptr, int base);
文字列をunsigned long型の数値に変換する。
#include <stdlib.h>
unsigned long int strtoul(const char *nptr, char **endptr, int base);
文字列をunsigned long long型の数値に変換する。
#include <stdlib.h>
unsigned long long int strtoull(const char *nptr, char **endptr, int base);
Microsoft 2023. データ型の範囲