C言語のきほん|整数定数と型のしくみを理解する

整数定数の書き方がわかると、C言語の型の動きがぐっと見えるようになる。

C言語では、変数に型があることはよく知られています。
たとえば int は整数、double は小数、といったように、どの種類の値を扱うかを型で表します。

でも、実は「定数」にも型があります。
たとえば 100、200U、300L、600LL のように書いた値は、ただの数字に見えても、C言語の中ではそれぞれ決まりにしたがって型が割り当てられています。

このしくみを理解しておくと、なぜある代入はそのまま通るのに、別の代入では警告が出るのか、なぜ同じ数値でも書き方によって型が変わるのか、といったことが見えてきます。
また、接尾語を使えば、符号なしにしたい、long にしたい、long long にしたい、といった意図を定数の時点ではっきり表せるようになります。

さらに、整数型を学ぶ流れの中では、負の数が内部でどのように表されているかも大切なポイントです。
C言語では、一般的に 2の補数という方法で負の数を表します。
この考え方を知っておくと、ビット表現や整数の計算のしくみへの理解がさらに深まります。

ここでは、整数定数の型の決まり、接尾語の役割、そして 2の補数の基本までを、順番にやさしく整理していきましょう。
数字をただの見た目として読むのではなく、「この定数はC言語の中でどう解釈されるのか」という視点で見られるようになるのが目標です。

整数定数にも型がある

最初に押さえておきたいのは、整数定数にも型があるということです。
たとえば 100 と書いたとき、C言語はそれを単なる数字の並びとして見ているのではなく、「これはどの整数型として扱うのが適切か」を判断しています。

普段はあまり意識しませんが、この判定はとても大切です。
なぜなら、定数の型によって、計算結果や代入時の扱いが変わることがあるからです。

たとえば次のようなコードを考えてみます。

int a = 100;

この 100 は、通常は int 型の整数定数として扱われます。
そのため、int 型の変数 a にそのまま自然に代入できます。

一方で、もっと大きな数を書くと、必ずしも int にはなりません。
C言語は、その値を表せる型を順番に探して、自動的に適切な型を選びます。

10進定数の型はどのように決まるのか

10進数で書かれた整数定数には、接尾語を付けない場合、自動的に型が選ばれるルールがあります。

10進定数では、基本的に次の順番で見ていきます。

10進定数での候補の順番意味
intまず int で表せるか確認する
longint で無理なら long を試す
long longlong でも無理なら long long を試す

つまり、10進定数は できるだけ符号付きの型で表そうとする のが基本です。

例を見てみる

定数解釈のされ方の例
100通常は int
50000環境によっては int、入らなければ long
2147483648int に入らなければ long または long long

ここで大事なのは、どの型になるかは処理系のサイズにも関係することです。
たとえば Windows 環境では long が 4バイトで int と同じ範囲になることが多いため、2147483648 のような値は long ではなく long long になる場合があります。

つまり、定数の型は「数字の大きさ」と「その環境の型の表現範囲」の両方で決まるのです。

8進定数や16進定数ではルールが少し違う

10進定数と比べて、8進定数や16進定数は型の選ばれ方が少し違います。
こちらは、より柔軟に符号なし型も候補に入ってきます。

接尾語を付けない 8進定数や16進定数では、一般に次の順番で型が検討されます。

8進定数・16進定数での候補の順番意味
intまず int を試す
unsigned int入らなければ unsigned int を試す
longさらに long を試す
unsigned longさらに unsigned long を試す
long longさらに long long を試す
unsigned long long最後に unsigned long long を試す

この違いは少し不思議に感じるかもしれませんが、8進数や16進数はビット列を意識して使われる場面が多いため、符号なし型との相性が良いことも関係しています。

例を見てみる

定数意味
0778進数
0xFF16進数
0xFFFFFFFF環境によっては unsigned int や unsigned long になることがある

たとえば 0xFFFFFFFF のような値は、10進定数よりも unsigned 系として解釈される可能性が高くなります。
ここが 10進定数との大きな違いです。

8進数と16進数の書き方も整理しておこう

整数定数は、10進数だけでなく、8進数や16進数でも書けます。
見た目の違いを知っておくと、コードを読んだときに混乱しにくくなります。

整数定数の主な書き方

書き方意味
10進数普通の整数表記100
8進数先頭に 0 を付ける077
16進数先頭に 0x または 0X を付ける0x64

たとえば、次の3つはすべて同じ値を表します。

表記10進数での値
100100
0144100
0x64100

見た目は違っても、中身としては同じ値です。
ただし、型の選ばれ方には違いが出ることがあるため、表記方法は思っている以上に重要です。

接尾語を付けると型を明示できる

整数定数には接尾語を付けることができます。
これを使うと、「この定数は unsigned にしたい」「これは long で扱いたい」といった意図をはっきり示せます。

主な接尾語

接尾語意味
U または uunsigned を表す200U
L または llong を表す300L
LL または lllong long を表す600LL

これらを組み合わせることもできます。

書き方意味
ULunsigned long
LUlong unsigned
ULLunsigned long long
LLUlong long unsigned

順序は入れ替えても構いません。
たとえば 400UL と 400LU は、どちらも unsigned long 型の整数定数です。

接尾語の具体例を見てみる

ここは実例で見たほうがわかりやすいです。

定数
200Uunsigned int
300Llong
400ULunsigned long
500LUunsigned long
600LLlong long
700ULLunsigned long long

このように、接尾語を付けると、C言語に任せるのではなく、書いた側が型をはっきり指定できます。

特に、大きな定数を書くときや、符号なしで扱いたい値を明確にしたいときにはとても便利です。

小文字の l より大文字の L を使うほうが安全

long を表す接尾語には l も使えますが、実際には大文字の L を使うほうがよいです。

その理由はとても単純で、小文字の l は数字の 1 と見分けにくいからです。

たとえば、次のような書き方は少し見づらくなります。

1000l

これよりも、次のように書くほうがわかりやすいです。

1000L

特に教材やチーム開発では、読みやすさはとても大切です。
long の接尾語には、なるべく大文字の L を使うようにすると安心です。

定数の型が自動で決まることを意識するのが大切

整数定数では、接尾語を付けなければ、C言語が自動で型を決めます。
この自動判定は便利ですが、意図しない型になることもあります。

たとえば、大きな16進定数が unsigned 系になることを知らないと、比較や演算の結果に驚くことがあります。
また、大きな10進定数が int ではなく long や long long になることを意識していないと、代入や printf の指定で混乱することがあります。

そのため、次のように考える習慣をつけるとよいです。

  • 小さな普通の数値なら、たいてい int
  • 大きな10進定数なら、long や long long になることがある
  • 16進数や8進数は unsigned 系になる場合がある
  • 意図を明確にしたいなら接尾語を使う

この視点を持つだけで、整数定数の見え方がかなり変わってきます。

サンプルプログラムで確認する

整数定数の書き方と接尾語の違いを確認しやすいシンプルなプログラム例です。

ファイル名:16_4_1.c

#include <stdio.h>

int main(void)
{
    /* いろいろな整数定数を用意する */
    int a = 100;
    unsigned b = 200U;
    long c = 300L;
    unsigned long d = 400UL;
    long long e = 500LL;
    unsigned long long f = 600ULL;

    /* それぞれの値を表示する */
    printf("整数定数の書き方を確認してみましょう。\n\n");

    printf("int 型の定数 a は %d です。\n", a);
    printf("unsigned 型の定数 b は %u です。\n", b);
    printf("long 型の定数 c は %ld です。\n", c);
    printf("unsigned long 型の定数 d は %lu です。\n", d);
    printf("long long 型の定数 e は %lld です。\n", e);
    printf("unsigned long long 型の定数 f は %llu です。\n", f);

    return 0;
}

このサンプルプログラムでわかること

このプログラムでは、接尾語の違いによって、どの型の定数になるかを見やすくしています。

特に確認したいポイントは次の通りです。

注目ポイント内容
100接尾語なしなので通常は int
200Uunsigned を明示している
300Llong を明示している
400ULunsigned long を明示している
500LLlong long を明示している
600ULLunsigned long long を明示している

このように、接尾語を使うと「この値をどの型として扱いたいか」がはっきり伝わります。

2の補数とは何か

ここからは、整数型の内部表現に関わる大切な話として、2の補数を見ていきましょう。

C言語では、一般的に負の数を 2の補数という方法で表しています。
これは、負の数をビット列でうまく扱うための仕組みです。

たとえば、8ビットで -5 を表したいとします。
そのときは、次のような手順で求めます。

-5 を 2の補数で表す手順

手順内容
1まず +5 を2進数で表す
2すべてのビットを反転する
3最後に 1 を足す

実際にやってみるとこうなります。

手順1 正の数 5 を2進数にする

00000101

手順2 ビットを反転する

11111010

手順3 1を加える

11111010 + 1 = 11111011

この結果、

11111011

が、8ビットで表した -5 の 2の補数表現になります。

2の補数の利点

2の補数が広く使われているのは、ちゃんと理由があります。
主な利点を整理すると次のようになります。

利点内容
加減算の回路を共通化できる減算を負の数の加算として扱える
ゼロが1種類だけになる0 の表現がひとつだけなので扱いやすい

加減算の回路を共通化できる

2の補数では、引き算を「負の数を足す計算」として処理しやすくなります。
そのため、コンピュータ内部では複雑な減算専用の回路を別に用意しなくても、加算の仕組みを応用しやすくなります。

これは、ハードウェア設計をシンプルにするうえで大きな利点です。

ゼロが1種類しかない

古い方式のひとつである 1の補数では、正のゼロと負のゼロの2種類が存在してしまいます。
これは計算や比較を複雑にしてしまいます。

その点、2の補数ではゼロは 00000000 の1種類だけです。
このおかげで、演算の扱いがすっきりします。

2の補数を知ると整数のしくみが見えやすくなる

整数定数の話をしていると、接尾語や型の判定ルールに目が向きやすいですが、実際にはその背後で「負の数はどう保存されるのか」という話もつながっています。

たとえば、signed 型が負の数を扱えるのは、内部的に 2の補数で表現しているからです。
そして、unsigned 型が負の数を扱わないのは、すべてのビットを正の値の表現に使っているからです。

つまり、整数定数の型と、整数の内部表現は、別々の話ではなくつながっています。
このつながりが見えてくると、C言語の整数に対する理解はかなり深まります。

この図は、整数定数に接尾語を付けないとき、C言語がどのような順番で型を選ぶのかを整理するための図です。
10進定数と、8進数・16進数では候補の順番が違うため、その違いを並べて見ると理解しやすくなります。

また、接尾語を付ければ型を明示できることも一緒に示しておくと、「自動判定」と「明示指定」の違いがつかみやすくなります。

この図は、2の補数の求め方を視覚的に理解するための図です。
文章だけだと少し機械的に感じる手順も、ビット列の変化を順番に並べることでかなりわかりやすくなります。

特に、正の数から出発して、反転して、最後に 1 を足す、という流れが見えると、「なぜ負の数がこの形になるのか」という感覚をつかみやすくなります。

整数定数を学ぶときに意識したいこと

このテーマでは、ただ書き方を暗記するだけでは少しもったいないです。
大事なのは、「C言語は整数定数を見たときに、どの型として扱うかを判断している」という視点を持つことです。

たとえば、次のように考えられるようになると理解が深まります。

意識したいこと内容
接尾語なしの定数自動的に型が選ばれる
10進定数基本は符号付き型が優先される
8進数・16進数unsigned 系が候補に入る
接尾語ありの定数型の意図を明示できる
負の数の内部表現一般に 2の補数で表される

この見方ができるようになると、整数の代入、比較、演算、ビット表現までがひとつにつながって見えてきます。
整数定数は単なる数字の書き方ではなく、C言語の型システムや内部表現と深く結びついている、と考えると理解しやすいです。

必要であれば次に続けて、同じ文体のまま
整数のオーバーフローと注意点符号付きと符号なしの比較で起こる落とし穴 まで、記事形式で続けて作れます。