C言語基礎|整数定数の表し方

0 を付けたつもりが “8進数”!? Cの整数定数は、書き方ひとつで値も型も変わります。

整数定数は「見た目」だけで判断すると危ないよ

C言語の整数定数(いわゆる整数リテラル)は、ただの数字の並びに見えます。
でも実際は、

  • 基数(10進 / 8進 / 16進)
  • 接尾語(U / L / LL など)
  • 処理系での型の範囲(int が何ビットか等)

この3つが合わさって、も決まります。

特に注意したいのが、先頭の 0。
例えば 013 は「13」じゃなくて、8進数の13(=10進数の11)です。
この勘違いは、ファイル権限(0644)みたいな場面では便利ですが、普通の数のつもりだと事故の元になります。

整数定数は3種類の基数で書ける

基数ごとの書き方(見分け方)

種類書き方のルール使える数字10進での値
10進定数先頭が 1〜9 で始まる(0 だけの 0 もOK)0〜913, 57, 013, 57, 0
8進定数先頭に 0 を付ける0〜7013, 077, 01011, 63, 8
16進定数先頭に 0x または 0X を付ける0〜9, A〜F, a〜f0xB, 0x12, 0Xff11, 18, 255

表の説明

  • 10進はいつもの数字。
  • 8進は 先頭 0 が合図。使える数字が 0〜7 だけ。
  • 16進は 0x が合図。A〜F が使えます(大文字小文字どちらでもOK)。

13 と 013 と 0x13 は別モノ

同じように見えて値が違う例

13    → 10進定数 → 10進で 13
013   →  8進定数 → 10進で 11
0x13  → 16進定数 → 10進で 19

図の説明
先頭の 0 や 0x は、単なる飾りではなく「この数は何進数か」を決める重要情報です。

整数接尾語(U / L / LL)は「型の指定メモ」

整数定数の末尾に付けられる U や L などは、その定数をどの型として扱ってほしいかを表すヒントです。

整数接尾語の意味

接尾語意味例のニュアンス
U / u符号無しにしてね100Uunsigned 系として扱う
L / llong にしてね100Llong 系として扱う
LL / lllong long にしてね100LLlong long 系として扱う
組み合わせ両方指定100UL, 100ULLunsigned long / unsigned long long

表の説明

  • 小文字 l は数字の 1 に似ていて紛らわしいので、実務では L を推奨です。
  • U と L は順序が前後しても意味は同じ扱いになることが多いですが、教材では UL / ULL のように分かりやすく書くのが安心です。

重要:負の数 -10 は「整数定数」ではない

ここ、地味に大事です。

  • 10 は整数定数(リテラル)
  • -10 は 10 に単項 - 演算子を付けた式

つまり、マイナス記号は「定数の一部」ではなく、演算子です。

-10 の正体

-10 = -(10)

説明
見た目は “負の定数” ですが、Cの文法的には「定数 + 演算子」です。
この違いは、型変換やオーバーフローの議論で効いてきます。

整数定数の「型」はどう決まる?

整数定数の型決定には、次の3要因が関わります。

型を決める3要因

要因具体例どう影響する?
値の大きさ1234567int に収まるなら int、無理なら long…のように段階的に上がる。
接尾語U, L, LLunsigned 系に寄せる、long 系に寄せる、などの方向づけ。
処理系の範囲INT_MAX の値そもそも int の最大値が環境で違うと判定結果も変わり得る。

表の説明
同じ 4000000000 でも、処理系の int が 32ビットかどうかで “収まる型” が変わり得ます。
だから標準では「こう決めなさい」という ルール(候補の順番)が定義されています。

10進定数の型決定ルール(接尾語ごと)

10進定数の接尾語と型の候補順

接尾語まず試す型 → ダメなら次へ
なしint → long → long long
Llong → long long
LLlong long
Uunsigned → unsigned long → unsigned long long
U と Lunsigned long → unsigned long long
U と LLunsigned long long

表の説明
“まず左から試して、表現できたらそれで確定” というルールです。
10進定数は、接尾語なしだと 符号付き側(int→long→long long)に進みます。

8進・16進定数の型決定ルール(接尾語ごと)

提示文の Table 7-12 も同じ考え方です。10進と違い、候補に unsigned が早めに入ります。

8進定数 / 16進定数の接尾語と型の候補順

接尾語まず試す型 → ダメなら次へ
なしint → unsigned → long → unsigned long → long long → unsigned long long
Llong → unsigned long → long long → unsigned long long
LLlong long → unsigned long long
Uunsigned → unsigned long → unsigned long long
U と Lunsigned long → unsigned long long
U と LLunsigned long long

表の説明
8進・16進はビット表現と相性がいいので、接尾語なしでも unsigned が候補に入ります。
この差が「同じ値でも10進と16進で型が違うことがある」理由です。

サンプルプログラム(別の例に変更・日本語メッセージ差し替え)

学習用として「値がどう違うか」「型の雰囲気がどう変わるか」を確認できるプログラム例です。

プロジェクト名:chap7-21-1 ソースファイル名:chap7-21-1.c

// 整数定数の基数(10進・8進・16進)を確認する
#include <stdio.h>

int main(void)
{
    int d = 13;     // 10進定数
    int o = 013;    // 8進定数(10進の11)
    int h = 0x13;   // 16進定数(10進の19)

    printf("整数定数は書き方で値が変わります。\n");
    printf("10進  : 13   = %d\n", d);
    printf("8進   : 013  = %d\n", o);
    printf("16進  : 0x13 = %d\n", h);

    return 0;
}

このプログラムで分かること

  • 13 / 013 / 0x13 は、別の基数なので値が違います。
  • 「先頭の 0 はゼロ埋め」ではなく、8進数の合図です。

ここで解説した命令(機能と書式)

この記事内で使った “命令(要素)” を、役割ベースで整理します。

登場要素の書式と役割

要素書式何をする命令?
整数定数(10進)13, 57, 010進数として整数値を表す
整数定数(8進)013, 0778進数として整数値を表す(先頭0が目印)
整数定数(16進)0xB, 0Xff16進数として整数値を表す(0xが目印)
整数接尾語100U, 100L, 100LL, 100ULL定数の型を unsigned / long / long long 方向へ寄せる
単項 - 演算子-x値の符号を反転する(-10 は -(10))
printfprintf(書式, 値, …)指定した書式で値を表示する

表の説明
“整数定数” は見た目のルールで値が決まり、
“接尾語” は型決定の優先順位に影響します。
そして - は定数の一部ではなく、値を反転する演算子です。

ありがちな落とし穴:先頭0のうっかり

  • 設定値やIDを 010 のつもりで書いたら 8 だった。
  • 09 のように 8進に存在しない数字を入れてコンパイルエラーになった。
  • ファイル権限の 0644 は意図的に8進。ここはむしろ正しい使い方

「先頭0を付ける文化」がある場面(権限・ビットマスク)と、そうでない場面(人数・金額・ID)を分けて考えるのがコツです。