
C言語基礎|標準規格と標準C
“方言C”で迷子にならない!標準規格(ISO/ANSI/JIS)と標準Cの流れを、今日ここでスッキリ整理しよう。
C言語って、同じCのはずなのに「環境によって動いたり動かなかったり」することがありますよね。
それ、だいたい 標準規格に対する解釈の差 や 独自拡張(方言) が原因です。
C言語が広まるほど、いろんなコンパイラや環境が増えて、便利な独自機能も増えました。
その一方で「別の環境に移植したらビルドが通らない…」みたいなことも起きやすくなります。
そこで重要になるのが 標準規格(Standard)。
この記事では、ISO/ANSI/JIS といった標準化の枠組みと、C89/C99/C11/C17…という“標準C”の世代を、表や図でしっかりつかめるように解説します。

そもそも「標準規格」って何?
標準規格は、ざっくり言うと 「C言語はこう振る舞う」っていう世界共通のルールブックです。
ルールがあるから、移植性(ポータビリティ)を高く保てます。
表:標準規格があると嬉しい理由
| 観点 | 標準規格がないと… | 標準規格があると… |
|---|---|---|
| 移植性 | 環境ごとに書き換えが必要 | 同じコードが動きやすい |
| 学習 | 本や資料が環境依存になりがち | 共通ルールで学べる |
| 品質 | “たまたま動く”が増える | 期待する動作を言語化できる |
| チーム開発 | 人によって前提がズレる | 合意点(ルール)を作れる |
表の説明
- 「標準に沿っているか?」が、コードの信頼性・移植性の土台になります。
- 逆に“方言に依存した便利機能”は、長期運用や移植で困りやすいです。
ISO / ANSI / JIS の関係
本文に出てきた組織名、ここで整理しましょう。
標準化のイメージ(ざっくり)
(米国国内規格)ANSI ──┐
├─→(国際規格)ISO/IEC 9899(Cの国際標準)
(各国の国内規格)JIS ──┘
図の説明
- ANSI は米国の標準化団体、ISO は国際標準化機構です。
- 実務上は「ANSIが先にまとまった → ほぼ同内容でISO化 → 国内規格(JIS)にも反映」という流れで語られることが多いです。
- だから日本では慣習的に ANSI C と呼ばれることがありましたが、世界標準としては「標準C(ISO C)」と捉えるのが自然です。
C89 / C90 / C99 / C11 / C17 って何?
C言語の標準規格は、何度も改訂されてきました。一般に「制定(または確定)年」で呼ばれます。
代表的な“標準C”の世代(覚え方つき)
| 呼び名 | だいたいの意味 | 目安になる特徴(超ざっくり) |
|---|---|---|
| C89 / C90 | 最初の本格的標準(ANSI→ISO) | 以後の基準になる“土台” |
| C99 | 1990年代の大改訂 | 便利な機能がいろいろ増える世代 |
| C11 | 2010年代の改訂 | 並行性/ライブラリ面など強化 |
| C17 | C11の小改訂(主に不具合修正寄り) | 大きな言語追加は少なめ |
| C23 | 2020年代の改訂 | 新しめの整理・追加(環境対応も) |
表の説明
- C17 は「仕様が2017年に固まった」という言い方がされ、出版年の都合で C18 と呼ぶ人もいます。中身は同じものを指すことが多いです。
- 現場では「自分のコンパイラがどの世代の標準をターゲットにしているか」が超重要になります。
「標準に準拠する」とはどういうこと?
ここ、ふわっとしがちなので言葉を揃えます。
よく出る用語の意味
| 用語 | 意味 | 例(イメージ) |
|---|---|---|
| 標準規格 | 仕様書そのもの(ルール) | ISO/IEC 9899 |
| 標準C | その規格に沿ったC言語 | C11準拠のC |
| 処理系(実装) | コンパイラ+ライブラリなど | gcc + 標準ライブラリ |
| 拡張 | 規格外の便利機能 | コンパイラ独自の構文など |
| 可搬性(移植性) | 環境を変えても動きやすい性質 | OSやCPUが違っても通る |
表の説明
- “標準Cで書く”とは、できるだけ規格に沿った書き方をすること。
- “拡張”は便利だけど、移植性の敵になりやすいので、使うなら意識して使うのがコツです。
自分の環境は「どの標準C」なの?(サンプルプログラム)
「今のコンパイラが標準Cのどの世代を想定しているか」を、マクロでざっくり表示するプログラムです。
プロジェクト名:chap14-2-1 ソースファイル名:chap14-2-1.c
#include <stdio.h>
int main(void)
{
/* C標準への準拠を示すマクロ(C89から) */
#ifdef __STDC__
printf("この処理系は、標準Cとして動作する設定です。\n");
#else
printf("この処理系は、標準Cとしての動作が保証されません。\n");
#endif
/* Cの世代を表す値(多くの処理系で定義される) */
#ifdef __STDC_VERSION__
printf("標準Cの世代を示す値(__STDC_VERSION__)は %ld です。\n", (long)__STDC_VERSION__);
/* よくある値を目安として判定する(環境により差があり得ます) */
if (__STDC_VERSION__ >= 202311L) {
printf("目安:C23 相当のモードです。\n");
} else if (__STDC_VERSION__ >= 201710L) {
printf("目安:C17 相当のモードです。\n");
} else if (__STDC_VERSION__ >= 201112L) {
printf("目安:C11 相当のモードです。\n");
} else if (__STDC_VERSION__ >= 199901L) {
printf("目安:C99 相当のモードです。\n");
} else if (__STDC_VERSION__ >= 199409L) {
printf("目安:C95(C90の修正版)相当のモードです。\n");
} else {
printf("目安:C90 相当のモードです。\n");
}
#else
printf("__STDC_VERSION__ が未定義です。目安:C90(または独自設定)相当の可能性があります。\n");
#endif
return 0;
}このプログラムで登場する項目の解説
図:マクロで“世代”を知る流れ
コンパイラのモード(例:C11など)
↓
定義されるマクロ(__STDC__ / __STDC_VERSION__)
↓
プログラムが表示する(今の標準Cの目安)
図の説明
- 「どの標準をターゲットにしてコンパイルしているか」で、定義されるマクロが変わります。
- つまり、コードの移植性を考えるなら「どの標準を前提にするか」を、先に決めるのが大事です。
重要:標準が違うと何が困る?
標準が違うと、文法・ライブラリ・未定義動作の扱いなどの“前提”がズレます。
標準差分で起きがちなトラブル例
| トラブル | よくある原因 | 対策の方向性 |
|---|---|---|
| ある環境ではビルドできるのに、別環境で失敗 | その機能が標準外 / 世代違い | ターゲット標準を決める |
| 同じコードなのに結果が違う | 未定義動作・処理系定義動作 | 規格に沿って安全に書く |
| 警告が大量に出る | 書式や型が標準とズレる | 警告をエラー扱いにして潰す |
表の説明
- “コンパイルが通る”は最低ラインで、標準準拠の意識があると品質が安定します。
- 未定義動作は特に怖いので、「標準が決めていない動き」を踏まないのがコツです。
現場でのおすすめの考え方
- チームや教材は「この標準で書く」を先に宣言(例:C11で統一)
- 拡張は使うなら明示的に(理由・範囲・代替を残す)
- ポータブルにしたい場所ほど標準に寄せる。
