導入
int は「少なくとも16ビット」としか規格で決まっておらず、実際のビット幅は環境によって変わります。「必ず8ビット」「必ず32ビット」と決め打ちしたい場面や、「サイズ・添字は必ず0以上」と保証したい場面のために、Cには専用の型が用意されています。
説明
stdint.h ― ビット幅を保証する整数型
<stdint.h> の uint8_t(符号なし8ビット)、int32_t(符号つき32ビット)のような型は、名前のとおりのビット幅であることがどの環境でも保証されています。通信プロトコルやファイル形式など、「このフィールドは必ず1バイト」のようにサイズが仕様で決まっている場面で特に重宝します。
size_t ― サイズ・添字専用の符号なし型
sizeof の結果や、配列の要素数を数えるときによく使う size_t は、「負の値を持たない、サイズを表すための」符号なし整数型です。printf でこの型の値を表示するときは、専用の書式指定子 %zu を使います。
stdbool.h ― true/falseを素直に書く
もともとCの真偽値は int の 0/0以外 で表現されていましたが(今も内部的にはその通りです)、<stdbool.h> をインクルードすると bool 型と true/false というキーワードが使えるようになり、コードの意図が読みやすくなります(bool の正体は _Bool という型の別名です)。
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
int main(void) {
uint8_t score = 250; /* 0〜255だけを表せる8ビット符号なし整数 */
int32_t total = 1000000; /* どの環境でも必ず32ビットの符号つき整数 */
printf("score=%u total=%d\n", score, total);
int numbers[5] = {1, 2, 3, 4, 5};
size_t len = sizeof(numbers) / sizeof(numbers[0]); /* 要素数。size_tは符号なし */
printf("len=%zu\n", len);
bool found = false; /* _Bool の別名。trueかfalseのどちらかしか入らない */
for (size_t i = 0; i < len; i++) {
if (numbers[i] == 3) {
found = true;
}
}
printf("found=%d\n", found); /* trueは1、falseは0として表示される */
return 0;
}
uint8_t は printf に渡すときに整数として昇格されるので、書式は %u(符号なし整数)で表示できます。bool の値を %d で表示すると 1/0 になります(専用の書式指定子はありません)。
可変長配列(VLA) ― サイズが実行時に決まる配列
これまでの配列は int arr[5]; のように、要素数を書いた時点(コンパイル時)で決まっていました。C99からは、要素数に変数を使える**可変長配列(VLA)**が使えます。
#include <stdio.h>
int main(void) {
int n = 4; /* 本来は計算結果や関数の結果など、実行時に決まる値 */
int arr[n]; /* 可変長配列:nの値でサイズが決まる */
for (int i = 0; i < n; i++) {
arr[i] = i * i;
}
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
VLAは便利ですが、確保される場所は(malloc で取るヒープではなく)スタックです。n が想定より大きな値になると、スタック領域を使い切ってプログラムが異常終了することがあります。実務では、上限をあらかじめ決めた固定サイズの配列にするか、大きくなりうるデータは第8章の malloc でヒープに確保する方が安全、という判断がよくされます。
やってみよう
uint8_t score に 255 より大きい値(たとえば 300)を入れるとどうなるか(8ビットに収まらない分が切り捨てられます)確かめてみましょう。VLAの n の値を変えて arr の中身と個数が変わることも試してください。
演習
uint16_t age に 25 を入れ、int scores[6] = {70, 85, 60, 90, 55, 40}; を用意してください。size_t len に sizeof(scores) / sizeof(scores[0]) を計算し、scores の中に 80 以上の値が1つでもあるかどうかを bool 変数に入れてください。最後に printf("age=%u len=%zu pass=%d\n", age, len, pass変数); の形で1行表示してください(正しく書けると age=25 len=6 pass=1 になります)。
ヒント1を見る
uint16_t age = 25;、int scores[6] = {70, 85, 60, 90, 55, 40};、size_t len = sizeof(scores) / sizeof(scores[0]); をこの順に用意します。
ヒント2を見る
bool pass = false; としてから for で scores[i] >= 80 になった回があれば pass = true; にし、最後に printf("age=%u len=%zu pass=%d\n", age, len, pass); で表示します。