プログラミング

2026年版 C言語 データ型サイズ比較表と移植性ガイド

ⓘ本ページはプロモーションが含まれています

スポンサードリンク

はじめに

int のサイズは本当に 4 バイトなのか」や「32bit と 64bit で型サイズが変わるとコードが壊れないか」といった疑問は、C 言語を扱うすべてのエンジニアが一度は抱えるものです。

本稿では次のことを実践的に解説します。

  • 標準データ型と固定幅整数型のサイズ比較表(環境別)
  • sizeof によるランタイム確認コード例
  • コンパイル時にサイズを保証する _Static_assert の使い方
  • 移植性確保のためのコーディング指針

最後に、オフラインでも参照できる PDF 版比較表 をダウンロードできるリンクをご用意しています。ぜひ開発環境に合わせて活用してください。


標準データ型サイズ比較(ILP32/LP64/LLP64)

データモデルとは

モデルintlongポインタ代表的 OS / コンパイラ
ILP324 バイト4 バイト4 バイト32bit Linux、組み込み系 GCC
LP644 バイト8 バイト8 バイト64bit Linux / macOS (glibc, clang)
LLP644 バイト4 バイト8 バイトWindows (MSVC)

ポイント
- int はどのモデルでも 4 バイト(32 ビット)に固定されていることが多いです。
- long とポインタだけがモデルごとに変わります。

標準データ型サイズ表

型 (C 標準)ILP32 (バイト)LP64 (バイト)LLP64 (バイト)
char111
short222
int444
long484
long long888
float444
double888
long double12*1616
void *488

* GCC がデフォルトで採用する x86 の long double は 12 バイト、Clang/MSVC は 16 バイトです。

解説

  • ILP32 – すべての整数型が 4 バイト以下に収まるシンプルなモデル。組み込み系やレガシー OS でよく見られます。
  • LP64 – Unix 系 OS のデファクトスタンダード。long とポインタが 8 バイトになるため、ファイルフォーマットやネットワークプロトコルでは int64_t 等の固定幅型を使うことが推奨されます。
  • LLP64 – Windows の独自モデル。long が 4 バイトに留まる点が他 OS と最大の相違です。そのため、Windows 向けコードでは sizeof(long) に依存しない設計が必須です。

まとめ
同一ソースでもビルド対象が LP64 か LLP64 かで sizeof(long) が異なる点に注意してください。バイナリ互換や外部データとのやり取りは、必ず固定幅型 (int*_t/uint*_t) を利用するのが安全です。


符号付き・符号なし整数の値域と注意点

代表的な型の範囲(十進表記)

バイト数符号あり最小値符号あり最大値符号なし最小値符号なし最大値
char1-1281270255
unsigned char10255
short2-32 76832 767065 535
unsigned short2065 535
int4-2 147 483 6482 147 483 64704 294 967 295
unsigned int404 294 967 295
long (LP64)8-9 223 372 036 854 775 8089 223 372 036 854 775 807018 446 744 073 709 551 615
unsigned long (LLP64)404 294 967 295

ポイント
符号付き整数は最上位ビットが符号に使われるため、同じバイト数でも正の最大値は 2^(N-1)-1 に制限されます(N はビット幅)。

実務でよくある落とし穴

ケース問題点回避策
配列インデックスに int を使用負のインデックスが計算される可能性インデックスは必ず size_t または unsigned にする
ファイルへ書き出す際に intunsigned int の変換を忘れる32bit 環境では問題なくても、64bit 環境で符号拡張が起こりデータが破損書き込み前に明示的にキャストし、範囲チェックを入れる
ビット演算で int を用いる演算結果が符号付きとして扱われ、予期せぬシフトが発生ビット単位の処理は必ず固定幅型 (uint*_t) で行う

まとめ
型サイズだけでなく「符号属性」も設計時に明示し、外部インターフェースや入出力チェックを徹底しましょう。


ポインタサイズの変化がもたらす実務上の影響

32bit ↔︎ 64bit のポインタ差

項目32bit 環境64bit 環境
ポインタサイズ4 バイト (32 ビット)8 バイト (64 ビット)
アラインメント(典型的な規則)4 バイト単位8 バイト単位
uintptr_t のサイズ4 バイト8 バイト

実務での具体例

1. 構造体サイズの膨張

コンパイラ / 環境sizeof(struct Node)
GCC (ILP32)8 バイト
GCC (LP64)16 バイト

注意:ネットワークプロトコルやファイルフォーマットで構造体をそのままシリアライズすると、ポインタサイズの違いによりデータがずれます。必ず明示的なパディングと固定幅型でレイアウトを定義してください。

2. メモリマッピング(組み込み系)

c

define REG_BASE ((volatile uint32_t *)0x40021000U)

uint32_t value = REG_BASE; / ポインタ自体は 32bit 固定 */

ポインタサイズが変わってもレジスタ幅は 32 ビットです。キャストミス に注意し、uintptr_t 経由で安全に整数化することを推奨します。

3. API 設計の落とし穴

64bit 環境で sizeof(void*) が 8 バイトになるため、32bit 用のバイナリと互換性がなくなります。代替案としては:

  • opaque ハンドラ(ポインタだけを外部に公開)
  • 固定幅整数 (uint64_t) に変換して保持

4. offsetof とパディングの検証

上記をビルドごとに実行し、期待通り 8 バイト(LP64)になっているか確認しましょう。

まとめ
ポインタサイズの変化は構造体レイアウト・シリアライズ・API の互換性に直結します。固定幅型とパディングチェックを必ず組み込むことが安全な移植の鍵です。


<stdint.h> の固定幅型と MSVC の実装詳細

固定幅整数型の保証内容

ビット幅符号標準上の保証
int8_t8符号付き常に 8 ビット符号付き整数
uint8_t8符号なし常に 8 ビット符号なし整数
int16_t16符号付き常に 16 ビット符号付き整数
uint16_t16符号なし常に 16 ビット符号なし整数
int32_t32符号付き常に 32 ビット符号付き整数
uint32_t32符号なし常に 32 ビット符号なし整数
int64_t64符号付き常に 64 ビット符号付き整数
uint64_t64符号なし常に 64 ビット符号なし整数

MSVC(2025 年版)での実装例

c
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;

typedef short int16_t; // 2 バイト保証 (MSVC は常に 16 ビット)
typedef unsigned short uint16_t;

typedef int int32_t; // 4 バイト保証
typedef unsigned int uint32_t;

typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;

  • long常に 4 バイト(LLP64)で、int64_t にはマッピングされません。
  • /Zc:__cplusplus オプションを有効にすると、C++ ヘッダーでも同様の型定義が利用できます。

size_t, ptrdiff_t, intptr_t の扱い

32bit 環境64bit 環境
size_t4 バイト8 バイト
ptrdiff_t4 バイト8 バイト
intptr_t4 バイト8 バイト

ポイント
ポインタと整数の相互変換が必要な場面では、必ず上記型を利用してください。直接 unsigned longlong にキャストすると、LLP64 環境でサイズ不一致が発生します。

移植性確保のための推奨事項

  1. 整数演算はすべて固定幅型 (int*_t, uint*_t) を使用。
  2. ポインタを整数に変換するときは uintptr_tintptr_t を介す。
  3. Windows 固有のサイズ依存コードは #if defined(_WIN64) / #elif defined(__linux__) で分岐させ、テストケースを必ず両環境で走らせる。

まとめ
<stdint.h> が提供する型は「ビット幅保証」そのものです。MSVC の実装差異に惑わされず、常に固定幅型でコードを書くことが最も安全な移植戦略です。


sizeof_Static_assert で自環境を検証する方法

ランタイム確認コード(例)

ビルド手順

環境コマンド
GCC / Clang (Linux/macOS)gcc -std=c11 -Wall -Wextra size_check.c -o size_check && ./size_check
MSVC (Developer Command Prompt)cl /std:c11 /Wall size_check.c && size_check.exe

実行結果は環境に合わせて変わりますが、自分のコンパイラが採用しているサイズをその場で確認できるので、移植前チェックに最適です。

コンパイル時検証(C11 の _Static_assert

コンパイルエラーが出たらすぐにサイズ不一致を検出できるので、CI パイプラインや組み込み向けビルドスクリプトに組み込むことを強く推奨します。

CI での自動チェック例(GitHub Actions)

yaml

まとめ
sizeof によるランタイム出力と _Static_assert によるコンパイル時検証を組み合わせれば、開発途中でもサイズズレを即座に捕捉できます。これが移植性確保の最も基本的な手段です。


移植性ベストプラクティスまとめ

手法具体例効果
固定幅型使用 (int*_t, uint*_t)uint32_t id;バイナリ互換・レジスタマッピングが保証される
コンパイル時サイズ検証 (_Static_assert)_Static_assert(sizeof(long) == 8, "LP64 前提");ビルドエラーで即座に問題を発覚
ポインタ⇔整数変換は uintptr_t / intptr_tuintptr_t addr = (uintptr_t)p;アーキテクチャ間のサイズ差に安全に対応
環境依存マクロで分岐 (#if defined(_WIN64))#ifdef _WIN64 // LLP64 用コード #else // LP64 用コード #endifソースが一目でどのプラットフォーム向けか判別可能
テストコードにサイズ出力を組み込む (printf("%zu", sizeof(...)))CI に size_check を走らせるビルドごとに実環境を自動検証
構造体レイアウトの明示的定義 (#pragma pack, static_assert(sizeof(struct) == ...))static_assert(offsetof(Node, next) == 8, "unexpected padding");パディングやアラインメントのずれを防止
外部データフォーマットは固定幅型で定義プロトコルヘッダ: uint16_t length; uint32_t crc;異なる環境でも同一バイト列になる

最終的な指針
1. 設計段階で「サイズが変わっても問題ない」かを明確に判断する
2. 固定幅型以外は必ず sizeof / _Static_assert で検証
3. プラットフォームごとの差異はマクロ分岐と CI テストで網羅



おわりに

本ガイドでは、データモデルごとのサイズ差符号付き・符号なし整数の値域, ポインタサイズが構造体や API に与える影響、そして <stdint.h> の固定幅型と MSVC の実装ポイント を網羅的に解説しました。

  • 標準データ型は環境依存で変化するため、必ず比較表を参照してください。
  • 移植性が求められるコードでは int*_t / uint*_t のみ を使用し、ポインタは uintptr_t 経由で扱うのが安全です。
  • ビルド時・実行時ともにサイズ検証を自動化すれば、環境差異によるバグはほぼ防げます。

「int のサイズが変わっても壊れない」コードを書く ことは、今日のマルチプラットフォーム開発において必須スキルです。ぜひ本記事と PDF 資料を手元に置き、日々の開発プロセスに組み込んでください。


スポンサードリンク

-プログラミング
-, , , , , , , ,