#データ型

C 言語のすべてのデータには型があり、コンパイラーはデータを操作する前にデータの型を認識する必要があります。いわゆる「型」とは、ある値のデータ型がわかれば、その値の特徴や演算方法がわかるようになります。

基本的なデータ型には、文字 (char)、整数 (int)、および浮動小数点数 (float) の 3 つがあります。複合型はそれらの上に構築されます。

##文字タイプ

文字型は個々の文字を参照し、型宣言では char キーワードを使用します。

char c = 'B';

上の例では、変数 c を文字型として宣言し、それを文字 B に割り当てます。

C 言語では、文字定数は一重引用符で囲む必要があると規定されています。

コンピュータ内部では、文字タイプは 1 バイト (8 ビット) を使用して保存されます。 C言語では整数として扱われるため、文字型は1バイト幅の整数となります。各文字は、整数「66」に対応する「B」など、整数 (ASCII コードによって決定される) に対応します。

文字タイプのデフォルトの範囲は、コンピュータによって異なります。一部のシステムはデフォルトで「-128」から「127」に設定され、他のシステムはデフォルトで「0」から「255」に設定されます。どちらの範囲も、「0」から「127」までの ASCII 文字範囲をカバーします。

文字型の範囲内にある限り、整数と文字は交換可能であり、文字型の変数に割り当てることができます。

char c = 66;
// と同等
char c = 'B';

上の例では、変数 c は文字型で、それに割り当てられる値は整数 66 です。これは、文字「B」に代入するのと同じ効果があります。

2 つの文字型変数は数学的演算を実行できます。

char a = 'B' // char a = 66 と同等;
char b = 'C' // char b = 67 と同等;

printf("%d\n", a + b); // 出力 133

上記の例では、文字型変数「a」と「b」の加算を2つの整数の加算とみなしています。プレースホルダー %d は 10 進整数の出力を示すため、出力結果は 133 になります。

一重引用符自体も文字です。この文字定数を表す場合は、バックスラッシュ エスケープを使用する必要があります。

char t = '\'';

上の例では、変数 t は一重引用符文字です。文字定数は一重引用符で囲む必要があるため、内部の一重引用符はバックスラッシュでエスケープする必要があります。

このエスケープされた書き込み方法は主に、ASCII コードで定義され、文字タイプの値にも属する一部の印刷不可能な制御文字を表すために使用されます。

  • \a: アラート。端末がアラームを鳴らすか点滅、あるいはその両方を鳴らします。
  • \b: Backspace キー。カーソルは 1 文字戻りますが、文字は削除されません。
  • \f: 改ページ文字。カーソルは次のページに移動します。最新のシステムでは、これは反映されなくなり、動作は \v のようなものに変更されます。
  • \n: 改行文字。
  • \r: 復帰文字。カーソルは同じ行の先頭に移動します。
  • \t: タブ文字。カーソルは次の水平タブ位置 (通常は次の 8 の倍数) に移動します。
  • \v: 垂直区切り文字。カーソルは次の垂直タブストップ (通常は次の行の同じ列) に移動します。
  • \0: コンテンツがないことを示すヌル文字。この値は数値 0 と等しくないことに注意してください。

エスケープ記述では、8 進数と 16 進数を使用して文字を表すこともできます。

  • \nn: 文字の 8 進表記、nn は 8 進数値です。
  • \xnn: 文字の 16 進表記。nn は 16 進値です。
文字 x = 'B';
文字 x = 66;
char x = '\102'; // 8 進数
char x = '\x42' // 16 進数

上記の例の 4 つの記述方法はすべて同等です。

整数型

導入

整数型は、より大きな整数を表すために使用され、型宣言では int キーワードが使用されます。

int a;

上の例では、整数変数 a を宣言しています。

int 型のサイズはコンピュータによって異なります。 int 型の値を格納するには 4 バイト (32 ビット) を使用するのが一般的ですが、2 バイト (16 ビット) または 8 バイト (64 ビット) も可能です。表現できる整数の範囲は次のとおりです。

  • 16 ビット: -32,768 ~ 32,767。
  • 32 ビット: -2,147,483,648 ~ 2,147,483,647。
  • 64 ビット: -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807。

署名済み、未署名

C 言語では、型が符号付きで負の値が含まれていることを示すために「signed」キーワードが使用され、型に符号がなく、ゼロと正の整数のみを表すことができることを示すために「unsigned」キーワードが使用されます。

int 型の場合、デフォルトで署名されます。これは、intsigned int と同等であることを意味します。デフォルトの状態なので、キーワード「signed」は省略するのが一般的ですが、書いても問題ありません。

署名済み int;
// と同等
int a;

int 型は符号を持たず、負でない整数のみを表すこともできます。この場合、変数はキーワード unsigned を使用して宣言する必要があります。

unsigned int a;

整数変数を「符号なし」として宣言する利点は、同じ長さのメモリで表現できる最大整数値が 2 倍になることです。たとえば、16 ビット signed int の最大値は 32,767 ですが、unsigned int の最大値は 65,535 に増加します。

「unsigned int」の「int」は省略できるので、上記の変数宣言は次のように書くこともできます。

署名なし;

文字タイプ char は、signed および unsigned に設定することもできます。

signed char c // 範囲は -128 ~ 127 です。
unsigned char c; // 範囲は 0 ~ 255 です。

C 言語では、「char」型にデフォルトで正符号があるか負符号があるかは、現在のシステムによって決定されると規定されていることに注意してください。これは、「char」が「signed char」と同等ではないことを意味します。「signed char」または「unsigned char」の可能性があります。これは、「signed int」と同等の「int」とは異なります。

整数のサブタイプ

int 型が整数を表すために 4 バイトまたは 8 バイトを使用する場合、これは小さな整数にとってスペースの無駄です。一方、状況によっては、より大きな整数が必要になり、8 バイトでは十分ではありません。これらの問題を解決するために、C 言語では int 型に加えて 3 つの整数のサブタイプが提供されています。これは、整数変数の範囲をより正確に制限するのに役立ち、コードの意図をより適切に表現するのにも役立ちます。

  • short int (short と省略): int よりも多くのスペースを必要とせず、通常は 2 バイトを占有します (整数の範囲は -32768 ~ 32767)。
  • long int (long と省略): int と同じくらいのスペース (少なくとも 4 バイト) を占有します。
  • long long int (long long と省略): long より多くのスペース (少なくとも 8 バイト) を占有します。
short int a;
長い整数 b;
Long Long int c;

上記のコードは、3 つの整数サブタイプの変数を宣言しています。

デフォルトでは、shortlong、および long long はすべて署名されます (signed)。つまり、signed キーワードは省略されます。また、符号なしで宣言して、表現できる最大値を 2 倍にすることもできます。

unsigned short int a;
unsigned long int b;
unsigned long long int c;

C言語ではintの省略が可能なので、以下のように変数宣言文を書くこともできます。

短いa;
unsigned short a;

ロングb;
符号なしロング b;

長い長い c;
unsigned long long c;

コンピュータが異なれば、データ型のバイト長も異なります。本当に 32 ビット整数が必要な場合は、「int」型の代わりに「long」型を使用する必要があります。これにより、4 バイト以上を確保できます。本当に 64 ビット整数が必要な場合は、「」型を使用する必要があります。 4バイト以上8バイト以上確保できるlonglong型。一方、スペースを節約するには、16 ビット整数のみが必要な場合は short 型を使用し、8 ビット整数が必要な場合は char 型を使用する必要があります。

整数型の制限値

現在のシステムのさまざまな整数型の最大値と最小値を確認する必要がある場合があります。C 言語のヘッダー ファイル limits.h には、signed char 型の最小値を表す SCHAR_MIN などの対応する定数が用意されています。 -128SCHAR_MAXはsigned char型の最大値127`を表します。

コードの移植性を高めるために、特定の整数型の制限値を知る必要がある場合は、これらの定数を使用するようにしてください。

  • SCHAR_MINSCHAR_MAX: signed charの最小値と最大値。
  • SHRT_MINSHRT_MAX: short の最小値と最大値。
  • INT_MININT_MAX: int の最小値と最大値。
  • LONG_MINLONG_MAX:longの最小値と最大値。
  • LLONG_MINLLONG_MAX:long long の最小値と最大値。
  • UCHAR_MAX: unsigned char の最大値。
  • USHRT_MAX: unsigned short の最大値。
  • UINT_MAX: unsigned int の最大値。
  • ULONG_MAX: unsigned long の最大値。
  • ULLONG_MAX: unsigned long long の最大値。

整数の底

C 言語の整数は、デフォルトではすべて 10 進数です。8 進数と 16 進数を表現したい場合は、特別な表現を使用する必要があります。

8 進数では、「017」、「0377」など、接頭辞として「0」が使用されます。

int a = 012; // 8 進数、10 進数の 10 に相当

16 進数では、「0xf」、「0X10」など、接頭辞として「0x」または「0X」が使用されます。

int a = 0x1A2B; // 16 進数、10 進数の 6699 に相当

一部のコンパイラは 2 進数を表す「0b」接頭辞を使用しますが、これは標準ではありません。

int x = 0b101010;

基数の違いは単に整数を記述する方法であり、整数の実際の格納方法には影響しないことに注意してください。すべての整数は、その記述方法に関係なく、バイナリ形式で保存されます。たとえば、「10 + 015 + 0x20」は正当な表現です。

printf()のbase関連のプレースホルダは以下の通りです。

  • %d: 10 進整数。
  • %o: 8 進整数。
  • %x: 16 進整数。
  • %#o: 0 を先頭に付けた 8 進整数を表示します。
  • %#x: 0x を先頭に付けた 16 進整数を表示します。
  • %#X: 0X を先頭に付けた 16 進整数を表示します。
int x = 100;
printf("dec = %d\n", x);
printf("8 進数 = %o\n", x); // 144
printf("hex = %x\n", x); // 64
printf("8 進数 = %#o\n", x);
printf("hex = %#x\n", x); // 0x64
printf("hex = %#X\n", x); // 0X64

浮動小数点型

小数点を含む数値は、コンパイラによって浮動小数点数として解釈されます。いわゆる「浮動小数点数」は、m * be の形式を使用して値を格納します。「m」は小数部分、「b」は基数 (通常は「2」) です。 「e」は指数部です。この形式は精度と数値範囲を組み合わせたもので、非常に大きい数値または非常に小さい数値を表すことができます。

浮動小数点数の型宣言では、浮動小数点数変数の宣言に使用できる float キーワードを使用します。

浮動小数点 c = 10.5;

上の例では、変数 c は浮動小数点型です。

「float」型は 4 バイト (32 ビット) を占め、そのうち 8 ビットは指数の値と符号を格納し、残りの 24 ビットは小数の値と符号を格納します。 float 型は少なくとも 6 桁の有効数字 (10 進数) を提供でき、指数部の範囲は (10 進数) -37 から 37 まで、つまり数値範囲は 10-37</sup です。 > から 10 37。

場合によっては、32 ビット浮動小数点数によって提供される精度や数値範囲では十分ではない場合があり、C 言語には他の 2 つのより大きな浮動小数点数型が用意されています。

  • double: 8 バイト (64 ビット) を占有し、少なくとも 13 の有効数字を提供します。
  • long double: 通常は 16 バイトかかります。

精度の制限により、浮動小数点数は単なる近似値であり、その計算は不正確であることに注意してください。たとえば、C 言語の「0.1 + 0.2」は「0.3」に等しくありませんが、多少の誤差があります。

if (0.1 + 0.2 == 0.3) // false

C 言語では、小数部と指数部を区切る文字「e」を使用する科学表記法を使用して浮動小数点数を表現できます。

double x = 123.456e+3; // 123.456 x 10^3;
// と同等
ダブルx = 123.456e3;

上記の例で、「e」の後にプラス記号「+」が続く場合、プラス記号は省略できます。科学的記数法では「e」の前後にスペースを入れることはできないことに注意してください。

また、科学表記法の小数部が「0.x」または「x.0」の形式の場合、「0」は省略できます。

0.3E6
// と同等
.3E6

3.0E6
// と同等
3.E6

ブール型

C 言語はもともとブール値に個別の型を設定せず、整数「0」を使用して false を表し、ゼロ以外のすべての値を使用して true を表していました。

int x = 1;
if (x) {
  printf("x は true!\n");
}

上記の例では、変数 x1 に等しく、C 言語はこの値が true を表すものとみなし、判定本体内のコードを実行します。

C99 標準では、ブール値を表すために型 _Bool が追加されました。ただし、この型は実際には整数型のエイリアスにすぎません。ここでは例を示します。

_Bool は正常です。

isNormal = 1;
if(正常です)
  printf("すべて問題ありません。\n");

ヘッダー ファイル stdbool.h は別の型エイリアス bool を定義し、1 を表す true0 を表す false を定義します。このヘッダー ファイルが読み込まれている限り、これらのキーワードを使用できます。

#include <stdbool.h>

ブールフラグ = false;

上記の例では、ヘッダー ファイル stdbool.h をロードした後、bool を使用してブール値の型を定義し、falsetrue を使用して true と false を表すことができます。

リテラル型

リテラルとは、コード内に直接現れる値を指します。

int x = 123;

上記のコードでは、「x」は変数、「123」はリテラルです。

リテラルはコンパイル時にメモリにも書き込まれるため、コンパイラは変数のデータ型を指定するのと同じように、リテラルのデータ型を指定する必要があります。

通常、10 進整数リテラル (123 など) はコンパイラによって int 型として指定されます。値が大きく、「int」で表現できる範囲を超える場合、コンパイラーはそれを「long int」として指定します。値が long int を超える場合は、 unsigned long として指定されます。十分な大きさでない場合は、long long または unsigned long long を指定してください。

10 進数 (例: 3.14) は double 型として指定されます。

リテラルの接尾辞

プログラマは、リテラルに別の型を指定したい場合があります。たとえば、コンパイラは整数リテラルを int 型として指定しますが、プログラマはそれを long 型として指定したいとします。この場合、接尾辞 l または L をリテラルに追加できます。そしてコンパイラは、このリテラルの型を long として指定する必要があることを認識します。

int x = 123L;

上記のコードでは、リテラル 123 にはサフィックス L が付いており、コンパイラはそれを long 型として指定します。ここで 123L123l と書かれており、効果は同じですが、小文字の l は数字の 1 と混同されやすいため、最初に L を使用することをお勧めします。

8 進数および 16 進数の値は、接尾辞 l および L を使用して、020L0x20L のように Long 型として指定することもできます。

int y = 0377L;
int z = 0x7fffL;

符号なし整数を「unsigned int」として指定したい場合は、接尾辞「u」または「U」を使用できます。

int x = 123U;

「L」と「U」を一緒に使用して、「unsigned long」型を表すことができます。 「L」と「U」の組み合わせの大文字と小文字の順序は関係ありません。

int x = 123LU;

浮動小数点数の場合、コンパイラはデフォルトで double 型を使用します。他の型を指定する場合は、10 進数の後に接尾辞 f (float) または l (long double) を追加する必要があります。

科学表記法では接尾辞も使用できます。

1.2345e+10F
1.2345e+10L

要約すると、一般的に使用されるリテラル接尾辞は次のとおりです。

  • f および F: float 型。
  • l および L: 整数の場合は long int 型、10 進数の場合は long double 型。
  • llおよびLL: 3LLなどのLong Long型。
  • u および U: 15U0377U などの unsigned int を表します。

「u」は他の整数接尾辞と組み合わせて、前または後ろに配置することもできます。たとえば、「10UL」、「10ULL」、および「10LLU」はすべて有効です。

以下にいくつかの例を示します。

int x = 1234;
長い整数 x = 1234L;
Long Long int x = 1234LL

unsigned int x = 1234U;
unsigned long int x = 1234UL;
unsigned long long int x = 1234ULL;

浮動小数点 x = 3.14f;
二重 x = 3.14;
ロングダブル x = 3.14L;

オーバーフロー

各データ型には数値範囲があり、保存される値がこの範囲を超える (最小値未満または最大値を超える) 場合、保存するためにより多くのバイナリ ビットが必要になり、オーバーフローが発生します。最大値より大きい場合はオーバーフローと呼ばれ、最小値より小さい場合はアンダーフローと呼ばれます。

一般に、コンパイラはオーバーフロー時にエラーを報告せず、コードを通常どおり実行しますが、余分なバイナリ ビットを無視し、残りのビットのみを保持するため、予期しない結果が生じることがよくあります。したがって、オーバーフローは回避する必要があります。

unsigned char x = 255;
x = x + 1;

printf("%d\n", x);

上の例では、変数「x」を「1」に加算すると、結果は「256」ではなく「0」になります。 x はタイプ unsign char であるため、最大値は 255 (バイナリ 11111111) であり、1256 の最上位ビット 1 (バイナリ 100000000) を追加するとオーバーフローが発生します。 ) は破棄され、残った値は 0 になります。

次の例をもう一度見てください。

unsigned int ui = UINT_MAX; // 4,294,967,295;
ui++;
printf("ui = %u\n", ui);
うい――;
printf("ui = %u\n", ui); // 4,294,967,295

上記の例では、定数 UINT_MAX が unsigned int 型の最大値です。 1 を追加すると、この型ではオーバーフローするため、0 が得られます。0 はこの型の最小値であり、その後 1 を減算すると、UINT_MAX が得られます。

オーバーフローは見落とされやすく、コンパイラーはエラーをスローしないため、十分に注意する必要があります。

for (unsigned int i = n; i >= 0; --i) // エラー

上記のコードは一見問題がないように見えますが、ループ変数 i の型は unsigned int であり、この型の最小値は 0 未満であり、0 未満の結果を取得することはできません。 i が 0 に等しい場合、1 を減算すると、-1 は返されませんが、unsigned int 型の最大値が返されます。この値は常に 0 以上であるため、無限ループ。

オーバーフローを回避するには、演算結果を型の制限値と比較するのが最善の方法です。

unsigned int ui;
符号なし整数の合計。

// 間違い
if (sum + ui > UINT_MAX) too_big();
それ以外の場合、合計 = 合計 + ui;

// 正しい
if (ui > UINT_MAX - 合計) too_big();
それ以外の場合、合計 = 合計 + ui;

上の例では、変数 sumui は両方とも unsigned int 型であり、それらが加算する合計も unsigned int 型のままであるため、オーバーフローが発生する可能性があります。ただし、「sum + ui」は常にオーバーフローの結果を返し、「UINT_MAX」を超えることはできないため、加算した合計が最大値「UINT_MAX」を超えるかどうかによってオーバーフローが発生したかどうかを判断することはできません。正しい比較方法は、UINT_MAX - sumui の間の大小関係を判断することです。

ここでもう一つ間違った書き方を紹介します。

unsigned int i = 5;
unsigned int j = 7;

if (i - j < 0) // エラー
  printf("ネガティブ\n");
それ以外
  printf("正\n");

上の例の演算結果は「正」を出力します。その理由は、変数 i と j が両方とも unsigned int 型であり、i - j の結果もこの型であり、最小値は 0 であり、それ以下の結果を得ることができないためです。 「0」よりも。正しい書き方は以下の通りです。

if (j > i) // ....

サイズ演算子

sizeof は C 言語によって提供される演算子で、特定のデータ型または特定の値が占めるバイト数を返します。そのパラメータは、データ型、変数名、または特定の値のキーワードにすることができます。

// パラメータはデータ型です
int x = sizeof(int);

// パラメータは変数です
int i;
サイズ(i);

// パラメータは数値です
サイズ(3.14);

上記の最初の例は、int 型が占めるバイト数 (通常は 4 または 8) を返します。 2 番目の例は、整数変数が占めるバイト数を返します。これは前の例とまったく同じです。 3 番目の例は、浮動小数点数「3.14」が占有するバイト数を返します。浮動小数点数リテラルは常に double 型として格納されるため、double 型は 8 バイトを占有するため、「8」が返されます。

C 言語では、「sizeof」演算子の戻り値が符号なし整数であることのみが規定されており、特定の型は指定されていません。代わりに、「sizeof」がどのような型を返すかはシステムに任されています。異なるシステムでは、戻り値の型は unsigned intunsigned long、さらには unsigned long long になる場合があります。対応する printf() プレースホルダーは %u%lu、および です。 %llu。これはプログラムの移植性を損なうものです。

C 言語は解決策を提供し、型エイリアス 'size_t' を作成して、'sizeof' の戻り値の型を統一的に表現します。このエイリアスは、stddef.h ヘッダー ファイル (stdio.h がインポートされるときに自動的に導入されます) で定義され、現在のシステムの sizeof の戻り値の型 (unsigned int など) に対応します。 またはunsigned long `。

C 言語には定数 SIZE_MAX も用意されており、これは size_t が表現できる最大の整数を表します。したがって、「size_t」が表現できる整数の範囲は「[0, SIZE_MAX]」となります。

printf() には、size_t 型の値を処理するために使用される特別なプレースホルダー %zd または %zu があります。

printf("%zd\n", sizeof(int));

上記のコードでは、sizeof の戻り値の型に関係なく、%zd プレースホルダー (または %zu) が正しく出力されます。

現在のシステムが %zd または %zu をサポートしていない場合は、代わりに %u (unsigned int) または %lu (unsigned long int) を使用できます。

型の自動変換

場合によっては、C 言語は値の型を自動的に変換します。

代入演算

代入演算子は、右側の値を左側の変数の型に自動的に変換します。

(1) 整数変数に浮動小数点数を代入する

浮動小数点数が整変数に割り当てられると、C 言語では小数部分を四捨五入せずに直接切り捨てます。

int x = 3.14;

上の例では、変数 x は整数型で、それに割り当てられる値は浮動小数点数です。コンパイラは自動的に 3.14 を最初に int 型に変換し、小数部分を破棄してからそれを x に代入するため、x の値は 3 になります。

この自動変換により一部のデータが失われる (「3.14」 では小数部分が失われる) ため、型を超えて値を代入しないようにし、変数と代入される値が同じであることを確認することをお勧めします。タイプ。

なお、小数点以下を切り捨てる場合は四捨五入ではなく、すべて切り捨てとなります。

int x = 12.99;

上の例では、「x」は四捨五入された「13」ではなく、「12」と等しくなります。

(2) 浮動小数点変数に整数を代入する

整数が浮動小数点変数に代入されると、その整数は自動的に浮動小数点数に変換されます。

浮動小数点数 y = 12 * 2;

上記の例では、等号の右側の整数が自動的に浮動小数点数に変換されるため、変数 y の値は 24 ではなく、24.0 になります。

(3) ナロータイプをワイドタイプに割り当てる

バイト幅の小さな整数型をバイト幅の大きな整変数に代入すると、型昇格が発生します。つまり、ナロー型がワイド型に自動的に変換されます。

たとえば、char または short 型が int 型に割り当てられている場合、それは自動的に int に昇格されます。

文字 x = 10;
int i = x + y;

上の例では、変数 x の型は char ですが、int 型に代入されているため、自動的に int に昇格されます。

(4) ワイド型をナロー型に割り当てる

バイト幅の大きい型がバイト幅の小さい変数に割り当てられると、その型はダウングレードされ、後者の型に自動的に変換されます。このとき、切り捨てが発生する可能性があり、システムは余分なバイナリ ビットを自動的に切り捨てるため、予測できない結果が生じます。

int i = 321;
char ch = i; // ch の値は 65 (321 % 256 の余り)

上の例では、変数 ch の型は char で、その幅は 8 バイナリ ビットです。変数 iint 型です。 ich に代入します。後者は i の最後の 8 桁のみを収容できます (バイナリ形式は 101000001、合計 9 桁です)。先頭の余分な 2 進数のビットは破棄され、残りの 8 ビットは '01000001' (10 進数で 65、文字 'A' に相当) になります。

整数型の値に浮動小数点数を代入した場合も切り捨てが発生し、浮動小数点数の小数部分が切り捨てられます。

二重円周率 = 3.14159;
int i = pi // i の値は 3 です。

上の例では、「i」は「3」に等しく、「pi」の小数部分は切り捨てられます。

混合型の操作

異なる型の値を混合計算に使用する場合、計算を実行する前に同じ型に変換する必要があります。変換ルールは次のとおりです。

(1) 整数と浮動小数点数の混合演算を行う場合、整数は他のオペランドと同じ型の浮動小数点数型に変換されます。

3 + 1.2 // 4.2

上記の例は int 型と float 型の混合計算で、int 型の 3 を float 型の 3.0 に変換して計算すると 4.2 が得られます。 。

(2) 異なる浮動小数点型を混在して演算する場合、「float」は「double」、「double」は「long」など、幅の小さい型が幅の大きい型に変換されます。ダブル`。

(3) 異なる整数型を混在して演算する場合、幅の小さい型が幅の大きい型に昇格します。たとえば、shortint に変換され、intlong に変換されます。場合によっては、符号付き型 signed が符号なしの unsigned に変換されることがあります。

次の例の結果は驚くべきものかもしれません。

int a = -5;
if (a < sizeof(int))
  do_something();

上の例では、変数 a は符号付き整数で、sizeof(int) は符号なし整数である size_t 型です。ルールによれば、signed int は unsigned int に自動的に変換されるため、「a」は自動的に符号なし整数「4294967291」に変換されます(変換ルールは、「-5」に符号なし整数の最大値を加え、さらに 1 を加えた値です)。そのため、比較が失敗し、do_something() は実行されません。

したがって、符号なし整数と符号付き整数に対する混合演算を避けることが最善です。このとき、C言語はsigned intをunsigned intに自動的に変換してしまうため、期待した結果が得られない可能性があります。

整数型の演算

同じ型の 2 つの整数を演算した場合、または 1 つの整数を演算した場合、一般に演算結果も同じ型に属します。ただし、幅が int より小さい型の場合は例外があり、演算結果は自動的に int に昇格されます。

符号なし文字 a = 66;

if ((-a) < 0) printf("negative\n");
else printf("ポジティブ\n");

上記の例では、変数 a は unsigned char 型です。この型は 0 より小さくすることはできませんが、-a は unsigned char 型ではないため、自動的に int 型に変換され、上記のコードが出力されます。ネガティブ。

次の例をもう一度見てください。

符号なし文字 a = 1;
unsigned char b = 255;
unsigned char c = 255;

if ((a - 5) < 0) do_something();
if ((b + c) > 300) do_something();

上記の例では、式 a - 5b + c が自動的に int 型に変換されるため、関数 do_something() が 2 回実行されることになります。

関数

関数のパラメータと戻り値は、関数定義で指定された型に自動的に変換されます。

int dostuff(int, unsigned char);

文字 m = 42;
unsigned short n = 43;
Long Long int c = dostuff(m, n);

上記の例では、パラメータ変数 mn は、元の型に関係なく、関数 dostuff() によって定義されたパラメータ型に変換されます。

以下は戻り値の自動変換の例です。

char func(void) {
  int a = 42;
  を返します。
}

上の例では、関数内の変数 aint 型ですが、戻り値は char 型です。これは、関数定義で返される型であるためです。

型の明示的な変換

原則として、予期しない結果を防ぐために、自動型変換は避けてください。 C 言語では型の明示的な変換が提供されており、手動で型を変換できます。

値または変数の前に括弧を使用して型 (type) を指定する限り、値または変数を指定された型に変換することができます。これを「キャスト」と呼びます。

(符号なし文字) ch

上記の例では、変数 ch を符号なし文字型に変換します。

long int y = (long int) 10 + 12;

上記の例では、「(long int)」は「10」を「long int」型に明示的に変換します。代入演算子によって右側の値が左側の変数の型に自動的に変換されるため、ここでの明示的な変換は実際には不要です。

ポータブルタイプ

C 言語の整数型 (short、int、long) は、コンピュータによって占有バイト幅が異なる場合があり、事前に占有バイト数を知ることはできません。

プログラマは、コードの移植性を高めるために、正確なバイト幅を制御することがあります。ヘッダー ファイル stdint.h は、新しい型のエイリアスを作成します。

(1) 正確な幅の整数型。特定の整数型の幅が確実であることが保証されます。

  • int8_t: 8 ビットの符号付き整数。
  • int16_t: 16 ビットの符号付き整数。
  • int32_t: 32 ビットの符号付き整数。
  • int64_t: 64 ビットの符号付き整数。
  • uint8_t: 8 ビット符号なし整数。
  • uint16_t: 16 ビット符号なし整数。
  • uint32_t: 32 ビット符号なし整数。
  • uint64_t: 64 ビットの符号なし整数。

これらはすべて型の別名であり、コンパイラはそれらが指す基になる型を指定します。たとえば、あるシステムでは、「int」型が 32 ビットの場合、「int32_t」は「int」を指し、「long」型が 32 ビットの場合、「int32_t」は「long」を指します。

以下に使用例を示します。

#include <stdio.h>
#include <stdint.h>

int main(void) {
  int32_t x32 = 45933945;
  printf("x32 = %d\n", x32);
  0を返します。
}

上記の例では、変数 x32 は型 int32_t として宣言されており、32 ビット幅であることが保証されています。

(2) 最小幅型。特定の整数型の最小長を保証します。

  • int_least8_t
  • int_least16_t
  • int_least32_t
  • int_least64_t
  • uint_least8_t
  • uint_least16_t
  • uint_least32_t
  • uint_least64_t

上記の型は、それらが占めるバイト数が指定された幅以上であることを保証できます。たとえば、「int_least8_t」は、8 ビットの符号付き整数を保持できる最小幅の型を表します。

(3) 整数計算が最も高速な最小幅タイプ(高速最小幅タイプ)。

  • int_fast8_t
  • int_fast16_t
  • int_fast32_t
  • int_fast64_t
  • uint_fast8_t
  • uint_fast16_t
  • uint_fast32_t
  • uint_fast64_t

上記の型はバイト幅を確保しながら最速の演算速度を追求したもので、例えば 8 ビット符号付き整数の場合は int_fast8_t が最速の演算速度型を表します。これは、一部のマシンは特定の幅のデータで最も高速に動作するためです。たとえば、32 ビット コンピュータは 16 ビット データよりも 32 ビット データで高速に動作します。

(4) ポインタを保存できる整数型。

  • intptr_t: ポインタ(メモリアドレス)を格納できる符号付き整数型。
  • uintptr_t: ポインタを格納できる符号なし整数型。

(5) 最大幅の整数型。最大の整数を格納するために使用されます。

  • intmax_t: 有効な符号付き整数を格納できる型。
  • uintmax_t: 有効な符号なし整数を格納できる型。

上記 2 つの型の幅は、long longunsigned long よりも大きくなります。


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0