C言語では、データ型はデータ要素の格納に関する意味論と特性を構成します。これらは、メモリ位置または変数の宣言という形で言語構文に表現されます。データ型はまた、データ要素の操作の種類や処理方法も決定します。
C言語は、整数型や実数型などの基本的な算術型と、配列型や複合型を構築するための構文を提供します。C標準ライブラリには、特定のハードウェアプラットフォーム上の言語実装に依存しない、正確なサイズのストレージを提供するなど、追加の特性を持つサポート型の定義が含まれています。[ 1 ] [ 2 ]
C言語には、4つの基本的な算術型指定子、、および(ブール型も含む)、そして修飾子、、、およびが用意されています。char次の表は、多数の記憶域サイズ固有の宣言を指定する際に許容される組み合わせを示しています。intfloatdoubleboolsignedunsignedshortlong
SCHAR_MIN == −128SCHAR_MAX == 127%hhi数値出力の場合%hhu数値出力の場合整数型の実際のサイズは実装によって異なります。規格では、データ型間のサイズ関係と各データ型の最小サイズのみが規定されています。
関係の要件は、 がlong longより小さくなく、longが より小さくなくint、 が より小さくないことですshort。charのサイズは常にサポートされている最小データ型であるため、他のデータ型(ビットフィールドを除く)は より小さくすることはできません。
の最小サイズは 8 ビット、と のchar最小サイズは16 ビット、は 32 ビットで、少なくとも 64 ビットを含まなければなりません。shortintlonglong long
型は、intターゲットプロセッサが最も効率的に処理できる整数型である必要があります。これにより、大きな柔軟性が得られます。たとえば、すべての型を 64 ビットにすることができます。ただし、いくつかの異なる整数幅スキーム (データ モデル) が広く使用されています。データ モデルは、異なるプログラムがどのように通信するかを定義するため、特定のオペレーティングシステム アプリケーション インターフェイス内では、統一されたデータ モデルが使用されます。[ 10 ]
実際には、charは通常 8 ビットのサイズで、shortは通常 16 ビットのサイズです (符号なしの対応物も同様です)。これは、1990 年代のSunOS 4 Unix、Microsoft MS-DOS、最新のLinux、組み込み 8 ビット PICマイクロコントローラ用の Microchip MCC18 など、さまざまなプラットフォームに当てはまります。POSIXではchar、サイズが正確に 8 ビットである必要があります。 [ 11 ] [ 12 ]
C 標準のさまざまな規則により、unsigned char配列に使用される基本型は任意の非ビットフィールドオブジェクトを格納するのに適しています。パディングビットやトラップ表現がないこと、オブジェクト表現の定義[ 8 ]、エイリアシングの可能性[ 13 ]などです。
浮動小数点型の実際のサイズと動作は、実装によって異なります。唯一の要件は、long doubleが より小さくなくdouble、 が より小さくないことです。通常、とにはそれぞれfloat32 ビットおよび 64 ビットのIEEE 754バイナリ浮動小数点形式が使用されます。floatdouble
C99規格には、で定義されている新しい実浮動小数点型とが含まれていますfloat_t。これらは、が 0、1、または 2 の場合の浮動小数点式の中間結果に使用される型に対応します。これらの型はよりも幅が広くなる場合があります。double_t<math.h>FLT_EVAL_METHODlong double
C99 では、複合型 、float _Complex、double _Complexも追加されましたlong double _Complex。C11では、仮想型 (C99 の情報付録に記載されています) 、 、 がfloat _Imaginary追加double _Imaginaryされましたlong double _Imaginary。ヘッダーを含めることで、これらのすべての型にそれぞれ<complex.h>と を使用してアクセスできるようになります。compleximaginary
C99 では、ブール型データ型 が追加されました_Bool。さらに、ヘッダーでは、この型の便利なエイリアスとして が<stdbool.h>定義され、および のマクロも提供されています。は通常の整数型と同様に機能しますが、例外が 1 つあります。 への変換では、値が 0 の場合は 0 (偽) が返され、それ以外の場合は 1 (真) が返されます。この動作は、暗黙的な縮小変換で発生する整数オーバーフローを回避するために存在します。たとえば、次のコードでは次のようになります。booltruefalse_Bool_Bool
unsigned char b = 256 ;if ( b ) { // 何らかの処理}変数のサイズが8ビットの場合、変数bはfalseと評価されますunsigned char。これは、値256がデータ型に収まらないため、下位8ビットが使用され、結果として値がゼロになるためです。ただし、型を変更すると、上記のコードは正常に動作します。
_Bool b = 256 ;if ( b ) { // 何らかの処理}また、この型は_Bool真の値が常に互いに等しいことを保証します。
_Bool a = 1 ; _Bool b = 2 ;if ( a == b ) { // このコードは実行されます}C23では、bool(およびその値trueとfalse)が言語の中核機能となり(の内容は<stdbool.h>廃止されました[ 14 ] [ 15 ])、次のようなコード例が可能になりました。
bool b = true ;if ( b ) { // このコードは実行されます}C23以降、この言語では、プログラマが任意のビット数の幅を持つ整数を定義できるようになりました。これらの型は、 として指定されます。ここで、Nは、符号付き型の場合は符号ビットを含めたビット数を2の補数で表した整数定数式です。Nの最大値は で提供され、少なくとも です。したがって、型(または)は-2から1までの値を取り、 は0から3までの値を取ります。型も存在し、0または1のいずれかであり、同等の符号付き型はありません。[ 16 ] C2Yの提案では、この制限を解除して を許可することが提案されており、これにより の特殊ケースが削除され、可能な値は0と-1になります。[ 17 ]_BitInt(N)BITINT_MAXWIDTHULLONG_WIDTH_BitInt(2)signed_BitInt(2)unsigned_BitInt(2)unsigned_BitInt(1)signed_BitInt(1)unsigned_BitInt(1)
C言語の仕様には、メモリ関連の量を表す型定義sとsが含まれています。これらのサイズは、利用可能なアドレス空間などのメモリ容量ではなく、対象プロセッサの演算能力に基づいて定義されます。これらの型は両方ともヘッダーファイルで定義されています。size_tptrdiff_t<stddef.h>
size_tは、特定の実装における任意のオブジェクト (配列を含む) のサイズを表すために使用される符号なし整数型です。演算子sizeof は、 型の値を返します。 の最大サイズは、ヘッダーで定義されているマクロ定数によって提供されます。は、少なくとも 16 ビット幅であることが保証されています。さらに、POSIX には、 と同じ幅の符号付き整数型である が含まれています。size_tsize_tSIZE_MAX<stdint.h>size_tssize_tsize_t
ptrdiff_tは、ポインタ間の差を表すために使用される符号付き整数型です。同じ型のポインタに対してのみ有効であることが保証されており、異なる型のポインタの減算は実装依存です。
基本算術型のサイズなどの実際の特性に関する情報は、2つのヘッダーファイル内のマクロ定数によって提供されます。1つは<limits.h>整数型用のマクロを定義するヘッダーファイル、もう<float.h>1つは浮動小数点型用のマクロを定義するヘッダーファイルです。実際の値は実装によって異なります。
CHAR_BIT– 文字型のサイズ(ビット単位)。一般的にはバイトサイズ(少なくとも8ビット)と呼ばれます。SCHAR_MIN、、、、(C99)SHRT_MIN –符号付き整数型INT_MINの最小値:signed char、signed short、signed int、signed long、signed long longLONG_MINLLONG_MINSCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX(C99) – 符号付き整数型の最大値: signed char、signed short、signed int、signed long、signed long longUCHAR_MAX、、、、(C99)USHRT_MAX –符号なし整数型UINT_MAXの最大値:unsigned char、unsigned short、unsigned int、unsigned long、unsigned long ULONG_MAXlongULLONG_MAXCHAR_MIN– 文字の最小値CHAR_MAX– 文字の最大値MB_LEN_MAX– マルチバイト文字の最大バイト数BOOL_WIDTH(C23) - ビット幅は_Bool常に1CHAR_WIDTHchar(C23) - ; CHAR_WIDTH、UCHAR_WIDTHおよびのビット幅は定義によりSCHAR_WIDTHに等しいCHAR_BITSCHAR_WIDTH、、、、(C23)SHRT_WIDTH- INT_WIDTH、、、、およびそれぞれのビット幅LONG_WIDTHLLONG_WIDTHsigned charshortintlonglong longUCHAR_WIDTH、、、、(C23)USHRT_WIDTH- UINT_WIDTH、、、、およびそれぞれのビット幅ULONG_WIDTHULLONG_WIDTHunsigned charunsigned shortunsigned intunsigned longunsigned long longFLT_MIN、、 – それぞれ float、double、long doubleDBL_MINのLDBL_MIN最小正規化正値FLT_TRUE_MIN、、 (C11 DBL_TRUE_MIN)LDBL_TRUE_MIN– float、double、long double のそれぞれ最小正値FLT_MAX、、– それぞれ float、double、long double の最大有限DBL_MAX値LDBL_MAXFLT_ROUNDS– 浮動小数点演算の丸めモードFLT_EVAL_METHOD(C99)-異なる浮動小数点型を含む式の評価方法FLT_RADIX– 浮動小数点型の指数部の基数FLT_DIG、、DBL_DIG– LDBL_DIGfloat、double、long double、それぞれで精度を失わずに表現できる10進数の桁数FLT_EPSILON、、–それぞれ float、double、long double のDBL_EPSILON1.0と次の表現可能な値との差LDBL_EPSILONFLT_MANT_DIG、DBL_MANT_DIG、 –浮動小数点仮数部の 基数桁LDBL_MANT_DIG数(それぞれ float、double、long double 型の場合)FLT_RADIXFLT_MIN_EXP、DBL_MIN_EXP、 –その数より 1 小さいべき乗が正規化された float、double、long double、それぞれとなるLDBL_MIN_EXP最小の負の整数FLT_RADIXFLT_MIN_10_EXP、、 – 10DBL_MIN_10_EXPをLDBL_MIN_10_EXPそのべき乗すると正規化された float、double、long double となる最小の負の整数、それぞれFLT_MAX_EXP、DBL_MAX_EXP、 –その数より 1 小さいべき乗が正規化された float、double、long double、それぞれとLDBL_MAX_EXPなるような最大の正の整数。FLT_RADIXFLT_MAX_10_EXP、DBL_MAX_10_EXP、LDBL_MAX_10_EXP– 10 をそのべき乗すると正規化された float、double、long double となる最大の正の整数、それぞれDECIMAL_DIG(C99) – サポートされている浮動小数点型の任意の数値を、DECIMAL_DIG桁の精度で10進数で表現し、値を変更せずに元の浮動小数点型で読み戻すことができる最小の10進数桁数。DECIMAL_DIGは少なくとも10です。C99規格には、プログラムの移植性を向上させるための新しい整数型の定義がいくつか含まれています。[ 2 ]既存の基本整数型は、実際のサイズが実装依存であり、システムによって異なる可能性があるため、不十分であると考えられました。新しい型は、ハードウェアが通常いくつかの型しかサポートしておらず、そのサポートが環境によって異なる組み込み環境<inttypes.h>で特に役立ちます。すべての新しい型はヘッダーで定義されており、<stdint.h>ヘッダーでも使用できます。型は次のカテゴリに分類できます。
以下の表は、実装の詳細を取得するためのタイプとインターフェースをまとめたものです(nはビット数を表します)。
この<inttypes.h>ヘッダーは、ヘッダーで定義されている型の機能を拡張する機能を提供します。で定義されている型に対応するprintf フォーマット文字列およびscanf フォーマット文字列<stdint.h>指定子のマクロと、および型を操作するためのいくつかの関数を定義します。 このヘッダーはC99で追加されました。<stdint.h>intmax_tuintmax_t
マクロは の形式です。ここで、{fmt} は出力フォーマットを定義し、(10 進数) 、(16 進数)、(8 進数)、(符号なし)、(整数) のいずれかです。{type}は引数の型を定義し、、、、のいずれかです。 は引数のビット数に対応します。PRI{fmt}{type}dxouinFASTnLEASTnPTRMAXn
マクロは の形式です。ここで、{fmt} は出力フォーマットを定義し、(10 進数) 、(16 進数)、(8 進数)、(符号なし)、(整数) のいずれかです。{type}は引数の型を定義し、、、、のいずれかです。 は引数のビット数に対応します。SCN{fmt}{type}dxouinFASTnLEASTnPTRMAXn
固定幅整数型と同様に、ISO/IEC TS 18661は、IEEE 754交換フォーマットおよび拡張フォーマットにおける浮動小数点型をバイナリおよび10進数で規定しています。
_FloatNバイナリ交換フォーマットの場合。_DecimalN10進数交換フォーマットの場合。_FloatNxバイナリ拡張フォーマットの場合。_DecimalNx10進数拡張形式の場合。すべてのデータ型には、T対応する型ポインタTがあります。ポインタは、特定の型の変数の格納場所のアドレスを含むデータ型です。ポインタは、*基本格納型の後にアスタリスク(*)型宣言子を付け、変数名の前に記述して宣言します。アスタリスクの前後の空白は省略可能です。
char * p ; long * q ; int * r ;ポインタデータ型に対してもポインタを宣言することができ、その結果、配列型へのポインタを含む、複数の間接ポインタ(など)が作成されますchar **。int ***後者はポインタの配列ほど一般的ではなく、その構文は紛らわしい場合があります。
char * pc [ 10 ]; // 'charへのポインタ'の10要素の配列char ( * pa )[ 10 ]; // charの10要素配列へのポインタ要素にはポインタpcのサイズ(一般的なプラットフォームでは通常40バイトまたは80バイト)のメモリブロックが10個必要ですが、要素はポインタ1つ(サイズ4バイトまたは8バイト)のみで、参照するデータは10バイトの配列()です。charpasizeof*pa==10
C言語にも「ポインタvoid」がありますvoid *。[ 18 ]「ポインタ」という名前は、メモリvoidを指していることを意味するのではなく(サイズのない不完全な型であるため)、型が指定されていない何かを指していることを意味します。逆参照する前に、別のポインタ型に変換する必要があります。は関数を指してはいけません。への呼び出しはを返し、を受け取ります。voidvoidvoid *mallocvoid *freevoid *
C では、有効なデータを参照しないポインタを表すためにヌルポインタの概念を使用します。マクロは、NULL可能な場合は暗黙的な型変換に依存して、ヌルポインタの代わりによく使用されます。ただし、この使用法は問題があり、プログラミング エラーの原因となる可能性があります。特に、の展開は、NULL実装に応じてポインタ型または整数型になる可能性があります。C23では、ヌルポインタ定数を表すために、定義済みの定数nullptrとその型nullptr_t(単一の値 を持つ) が導入されました。は明確にポインタであり、任意のオブジェクト ポインタまたは関数ポインタに変換でき、の特定のケースを許可します。[ 19 ]この型のサイズとアライメントは、文字型 (または ) へのポインタと同じですが、他のポインタ型はサイズとアライメントが異なる場合があるため、すべてのヌルポインタを で置き換えることはできません。[ 20 ]nullptrnullptrnullptr_t_Genericvoid *nullptr
void 型Tと関数型を除くすべての型に対して、 「型の要素の配列」という型が存在します。配列とは、すべて同じ型の値の集合であり、メモリ上に連続して格納されます。サイズの配列は、からまでの整数でインデックス付けされます。以下に簡単な例を示します。NTN0N − 1
int a [ 10 ]; // 10個の要素からなる配列、各要素の型はint配列は複合初期化子で初期化できますが、値を代入することはできません。配列は、最初の要素へのポインタを渡すことで関数に渡されます。多次元配列は「配列の配列...」として定義され、最外次元を除くすべての次元はコンパイル時定数サイズである必要があります。
int aa [ 10 ][ 8 ]; // 10個の要素からなる配列。各要素は「8個のint型要素の配列」型。charC言語では、文字列はしばしば( )の配列として格納されますが、これは( )char[]へのポインタとは異なります。は再割り当てできず、定義された場所に存在しますが、は再割り当て可能ですが、変更することはできません。charchar *char[]char *
char s [] = "Hello, world!" ; char * p = s ; // s は &s[0] に変化し、p は最初の文字を指す関数がT[]パラメータとしてを受け取る場合でも、それはT *最初の要素を指すに分解されます。
void f ( int a []);// これは以下と同じです: void f ( int * a );配列のインデックス付けはポインタ演算の観点から定義され、つまり、a[i]と同等である*(a + i)。[ 21 ]
C言語では、列挙型は、値が名前付き定数のセットに制限されている整数型です。[ 22 ]列挙型は前方宣言できません。列挙型には値を直接代入することもでき、switch複数のケースを列挙するためによく使用されます。
#include <stddef.h>enum Status { OK = 200 , NOT_FOUND = 404 , SERVER_ERROR = 500 };const char * get_status_string ( enum Status status ) { switch ( status ) { case OK : return "成功" ; case NOT_FOUND : return "見つかりません" ; case SERVER_ERROR : return "サーバーエラー" ; default : unreachable (); } }列挙定数はコンパイル時に既知であり、マクロよりも安全な方法で整数定数を定義することが多いです。列挙型の基底サイズは通常 ですintが、C23 以降では、列挙型の基底サイズを任意の整数型に直接指定できるようになりました。
enum Color : char { RED = 1 , ORANGE , YELLOW , GREEN , BLUE , INDIGO , VIOLET };列挙型は型安全性が保証されていないため、別の列挙型の値を代入することができます。また、列挙型には、定義済みの値の範囲内の値を必ずしも代入する必要はありません。
enum Color color = YELLOW ; // YELLOW = 3 enum Month month = JUNE ; // JUNE = 6color = month ; // 色は現在 6 (インディゴ) です。month = 999 ; // 列挙型の Month には 999 の値がないかもしれませんが、それでも許可されます。構造体(structs)は、異なるデータ型を持つ複数のデータ項目を、単一の変数で参照される連続したメモリブロックに集約します。メモリの整列のためにメンバーにパディングが加えられる場合があるため、効率的なメモリ使用のためには、フィールドをサイズの大きい順から小さい順に並べることが推奨されます。
struct Student { char name [ 50 ]; unsigned int id ; unsigned int semester ; float gpa ; };// 位置初期化 - 値はフィールドの順序に一致しますstruct Student alice = { " Alice" , 123 , 2 , 3.8 }; // 指定初期化子 (C99 以降) struct Student bob = { .name = " Bob" , .id = 246 , .semester = 1 , .gpa = 3.9 } ;構造体は、フィールドが同じ記憶単位を共有できるようにするためにビットフィールドを使用することもできますが、レイアウトは実装依存です。
struct Properties { // 3 つのフィールドは 1 バイトにコンパクトにパックできますunsigned char visible : 1 ; // a は 1 ビットを占めますunsigned char color : 3 ; // b は 3 ビットを占めますunsigned char size : 4 ; // c は 4 ビットを占めます};構造体のメモリレイアウトは、いくつかの制約はあるものの、各プラットフォームの言語実装の問題です。最初のメンバのメモリ アドレスは、構造体自体のアドレスと同じでなければなりません。構造体は、複合リテラルを使用して初期化または代入できます。関数は構造体を直接返すことができますが、これは実行時に効率的でないことがよくあります。C99 以降、構造体はフレキシブル配列メンバで終了することもできます。
関数は構造体を値渡しでパラメータとして受け取ることができますが、構造体全体をコピーするためコストがかかります。一方、ポインタのサイズは既知(通常は4バイトまたは8バイト)であるため、ポインタで渡す方が多くの場合好ましいです。
#include <stdio.h>// 値渡しvoid print_student ( struct Student s ) { printf ( "名前: %s、ID: %d、学期: %d、GPA: %.2f \n " , s . name , s . id , s . semester , s . gpa ); }// ポインタによる受け渡しvoid print_student ( struct Student * s ) { printf ( "名前: %s、ID: %d、学期: %d、GPA: %.2f \n " , s -> name , s -> id , s -> semester , s -> gpa ); }構造体は他の構造体で構成できます。
struct Date { int year ; int month ; int day ; };struct Birthday { char name [ 50 ]; struct Date dob ; };自身の型の構造体へのポインタを含む構造体は、リンクされたデータ構造を構築するためによく使用されます。
struct LinkedList { void * item ; // 現在の項目を格納しますstruct LinkedList * next ; // 次のリストを格納します。次の項目がない場合は NULL を格納します};共用型とは、異なる型記述を選択することで、同じメモリブロックへのアクセスを可能にする特殊な構造です。
// 整数または浮動小数点値のいずれかを保持しますunion Number { int i ; float f ; } d ;d.i = 10 ; // d には 10 が格納されるd.f = 3.14f ; // dには 3.14が格納され、10 が上書きされる次の例では、データ型の共用体を宣言することで、同じデータを整数、浮動小数点数、またはその他のユーザー定義型として読み取ることができるようになります。
union { int i ; float f ; struct { unsigned int u ; double d ; } s ; } u ;の合計サイズはuのサイズであり、これはとu.sのサイズの合計になります。これは がと の両方よりも大きいためです。 に何かを割り当てる場合、が より小さい場合は、 の一部が保持される可能性があります。u.s.uu.s.dsifu.iu.fu.iu.f
組合員から値を読み取ることは、組合員の値が変換されるのではなく単に読み取られるだけなので、キャスティングとは異なります。
関数ポインタを使用すると、特定のシグネチャを持つ関数を参照できます。たとえば、標準関数のアドレスをabs変数に格納するには、次のようにしますmy_int_f。
int ( * my_int_f )( int ) = & abs ; // & 演算子は省略できますが、ここで abs の「アドレス」が使用されていることを明確にします関数ポインタは、通常の関数呼び出しと同様に、名前で呼び出されます。
#include <stdio.h> #include <stdlib.h>int ( * my_abs )( int ) = & abs ; int x = -42 ; int abs_of_x = my_abs ( x ); printf ( "abs(%d) = %d \n " , x , abs_of_x );前述の型は、型修飾子によってさらに特徴付けられ、修飾型が得られます。2014年現在C11では、標準Cには4つの型修飾子があります。
const( C89 )volatile( C89 )restrict( C99 )_Atomic(C11)-後者はユーザー名との衝突を避けるためにプライベート名が付けられているが[ 23 ] 、ヘッダーが含まれている場合はより一般的な名前を使用できる。 atomic<stdatomic.h>これらのうち、constは最もよく知られ、最もよく使われている修飾子であり、 C 標準ライブラリに登場し、定数の正しさを満たす必要がある C 言語の重要な使用において必ず遭遇します。他の修飾子は主に低レベルプログラミングに使用されます。は、変数がいつでも変更される可能性があることを示唆することで、変数に対するコンパイラの最適化を抑制することを目的としています。は、ポインタが指すオブジェクトにはそのポインタのみがアクセスすることを示し、は、オブジェクトが「アトミック」である、つまり読み取りと書き込みが不可分であることを示します。volatilerestrict_Atomic