【第2回】C言語のデータ型と変数:メモリサイズとデータの表現を理解しよう
1. はじめに:データ型と変数の基礎を学ぶ理由
前回は、MacのClang環境を使って printf() による出力と、コンパイルから実行までの基本的な流れを確認しました。
C言語を学ぶうえで次に重要になるのが、データを一時的に保存するための「変数」と、そのデータがコンピュータ上でどのように解釈されるかを決める「データ型」です。
PHPなどの高水準な言語では、データ型をそこまで深く意識しなくても自動的に処理してくれますが、C言語ではプログラマ自身が適切なデータ型を選んで扱う必要があります。
今回は、C言語におけるデータ型とバイト数の関係、変数の命名規則、マクロ定義(#define)やリテラル表記、そして文字コードの仕組みについて確認していきましょう。
2. C言語におけるデータ型とバイト数
C言語では、扱うデータの種類や大きさ(範囲)に応じて様々なデータ型が用意されています。
また、コンピュータの内部において、それぞれのデータ型が何バイトの領域を使用するのかという「メモリサイズ」の意識が非常に重要になります。
データ型とバイト数の基本(環境依存性)
C言語のデータ型は大きく「整数型」と「実数型(浮動小数点数)」に分類されます。
なお、C言語の仕様上、sizeof(char) は必ず 1 byte ですが、1 byte が必ず 8 bit とは限らない(一般的なPC環境では 1 byte = 8 bit として扱われます)という特徴があります。
また、具体的なバイト数は環境によって異なります(以下のサイズは一般的なMacの64bit環境の例です)。
■ 整数型
char/unsigned char: 1 byte(charは必ず 1 byte)short/unsigned short: 通常 2 byteint/unsigned int: 環境依存(Macの64bit環境では通常 4 byte)long/unsigned long: 環境依存(Macの64bit環境では通常 8 byte)
■ 実数型(浮動小数点数)
float: 4 byte(単精度)double: 8 byte(倍精度)
sizeof 演算子で型サイズを確認する
C言語ではデータ型のサイズが環境によって異なるため、実際のサイズを確認するには sizeof 演算子を使用します。
例えば、以下のようなコードを実行することで、手元の環境における各データ型のサイズ(バイト数)を確認できます。
#include <stdio.h>
int main(void) {
printf("char: %zu byte\n", sizeof(char));
printf("int: %zu byte\n", sizeof(int));
printf("long: %zu byte\n", sizeof(long));
printf("float: %zu byte\n", sizeof(float));
printf("double: %zu byte\n", sizeof(double));
return 0;
}
C言語では、このようにデータ型によって必要なメモリ領域の大きさや、値をどのように解釈するかが変わってきます。
unsigned(符号なし)とは?
整数型などの頭に付く unsigned は、「符号なし」を意味します。
unsigned char のような符号なし整数型では、負の数を扱わない代わりに、同じビット幅でより大きな正の数を扱えます。
なお、通常の char が符号付きか符号なしかは処理系によって異なります。符号付きの char を明示したい場合は signed char を使用します。
3. 変数の命名規則とマクロ定義・リテラル表記
C言語で変数や値を使う際には、いくつかのルールや便利な書き方があります。
変数の命名規則
変数名を付ける際は、以下のルールを遵守する必要があります。
- 使用可能な文字: アルファベット(
a-z,A-Z)、数字(0-9)、アンダーバー(_) - 先頭文字の制限: 先頭に数字は指定不可
- ×:
int 1value; - ○:
int value1;
- ×:
- 大文字・小文字の区別: あり(
TIMEOUTとtimeoutは別の変数として区別されます) - 予約語の禁止: C言語の登録単語・関数名(
int,if,printfなど)は使用できません
マクロ定義(#define)とリテラル表記
■ マクロ定義 (#define)
#define を使うと、プリプロセッサによって指定した文字列や数値などにマクロが置き換えられます。慣習として、定数用途のマクロ名には大文字を使用することが多いです。
#define SERVER_NAME "SS-Infra API Server"
■ 文字定数 (char)
char 型に半角1文字を代入する際は、シングルクォーテーション ' ' で囲みます。
char server_grade = 'A';
■ リテラルの型指定サフィックス(接尾辞) 明示的に数値の型を指定する場合、末尾に記号を付与します(省略可能)。
- 符号なし (
unsigned): 末尾にUを付ける(例:unsigned int max_retry = 5U;) long型: 末尾にLを付ける(例:long total_requests = 5000000L;)float型: 末尾にFを付ける(省略するとdouble型扱いとなります)
4. 文字と文字コードの仕組み
C言語の char 型は、主に1文字を扱うために使用されます。ただし、C言語における char 型とASCIIコードは同義ではありません。
C言語では実行文字セットに基づいて文字が表現されますが、一般的なPC環境ではASCII互換の文字コードが使用されているため、例えば 'A' は数値 65 として扱われます。
このように、C言語では文字も内部的には整数値として扱われるため、文字コードの仕組みを理解することが後々の文字列処理を学ぶうえで重要になります。
5. 実装サンプルと変換指定子・エスケープシーケンス
これまで紹介したデータ型や変数をすべて使ったサンプルコードを作成し、実際の出力結果とフォーマット指定方法を確認してみましょう。
実装サンプルプログラム
今回は、サーバーの設定情報や稼働状況を模したデータを出力するプログラムを作成します。
以下のコードを server_info.c などのファイルで作成してみましょう。
#include <stdio.h>
int main(void) {
#define SERVER_NAME "SS-Infra API Server"
int port = 8080;
char server_grade = 'A';
unsigned int max_retry = 5U;
long total_requests = 5000000L;
float cpu_load = 2.45F;
printf("システム名: \"%s\"\n\tport: %d ランク: '%c' 最大リトライ: %u 総リクエスト: %ld CPU負荷: %.2f%%\n",
SERVER_NAME, port, server_grade, max_retry, total_requests, cpu_load);
return 0;
}
変換指定子とエスケープシーケンス一覧
printf() で変数の値を画面に表示する際には、それぞれの型に応じた変換指定子を使用します。
-
変換指定子:
%d:int型(10進数整数)%c:char型(1文字)%u:unsigned int型(符号なし10進数整数)%ld:long型(ロング整数)%f:float/double型(実数)%s: 文字列
-
エスケープシーケンス(特殊文字):
\n: 改行\t: タブ(文字の位置揃え)\": ダブルクォーテーションの文字出力\': シングルクォーテーションの文字出力\\: バックスラッシュ自体の出力
6. まとめと次回予告
今回は、C言語の基本データ型と変数の仕組み、環境依存のバイト数、そしてリテラルの使い方を確認しました。
今回学んだ内容を整理すると、次のとおりです。
- データ型には整数型や実数型があり、それぞれ決められたメモリサイズ(バイト数)を持つ
- バイト数やサイズは環境依存であり、
sizeof演算子で確認できる unsignedを使うことで符号なしの大きな数値を扱えるchar型の内部は数値として管理されており、文字コードを介して扱われるprintf()では、型に応じた変換指定子を使って値を出力する
今回の内容を通して、C言語がどのようにデータをメモリ上に保持し、型を意識して扱っているのかが少し見えてきたかと思います。
次回は、複数のデータをまとめて扱う「配列・文字列」の仕組みや、計算を行うための「演算子」について学びます。実際のコードを動かしながら、より実践的なプログラムの書き方を確認していきましょう。
【お役立ちツールのご案内】
C言語やPHPの学習を進める中で、ご自身の書いたコードや既存のプロジェクトにセキュリティ上のリスクや古い書き方(非推奨関数など)が混ざっていないか気になった際は、安全な字句解析(
token_get_all())で一括スキャンできる当サイトの PHPレガシーコードスキャナー もぜひご活用ください。