文字リテラルの型

C と C++ で文字リテラルにつく型が異なります。
C では int, C++ では char になるようです。

$ cat clit.c
#include <stdio.h>
int main() {
  printf("%u\n", sizeof 'x');
  return 0;
}
$ gcc clit.c && ./a.out
4
$ g++ clit.c && ./a.out
1

このことについて考察してみます。

なぜ C++ の文字リテラルは char なのか?

C++ が C から仕様をあえて変更したのには理由があるはずです。これはおそらく関数のオーバーロードがあるからでしょう。

C では char を取る関数

void f(char c);

に int を渡すと勝手に char に変換されることが保証されていますが、C++ ではそうとは限りません。

void f(int n);

も同時に存在するかもしれないからです。

例えば文字リテラルがint型を持つと
cout << 'x';
で 120 が表示されます。これはひどい

というわけで、C++ が文字リテラルの扱いを変更したのは納得がいきます。

なぜ C の文字リテラルは int なのか?

普通に考えて、文字リテラルは char型を持つほうが自然です。
ではなぜ C は int にしてしまうのか。理由を3つほど考えました。

処理系の実装が楽になる

文字リテラルをlexingした段階で、内部では整数リテラルとして扱うことが可能なので、文字リテラルの処理がちょびっと楽になる。プリプロセッサで整数リテラルに書き換えちゃうのもあり。

拡張性

マルチバイト文字とか。処理系が独自に何か拡張する余地はあるような気がする。
gccでは一応 'あ' とか書けるようです。使えないけど。なんと g++ でも 'あ' とか書くと1バイトでなく4バイトになる。

ライブラリ関数とインターフェースを合わせる

getchar() の返り値が int だとか (これはEOFのためだよね)、 の isXXXX() の引数が int だとか、その辺とインターフェースを合わせておくというのは自然なことだと思う。

    • -

まぁ、どれも後付けっぽいし、あんまり深く考えてなかったのかもしれませんけど。

Cのコア部分に関しては文字というものを意識することはほとんどありません。

Cプログラムはカーネルにwriteシステムコールを呼んでバイト列を処理してもらうだけだし、カーネルは端末にバイト列を送りつけるだけです。ただのバイト列を文字として表示するのは端末の責任です。

たいがいの文脈においては、Cプログラムにとって文字とはただの数字にすぎず、charは1バイトのデータでしかありません。

唯一「char = 文字」っぽい振る舞いをするのは、文字列リテラルが const char * になることぐらいでしょうか。
文字列リテラルがcharのポインタなのに 文字リテラルはintってのは、たいへん据わりが悪ぃです。

ライブラリの層になると、scanfが空白文字を飛ばしたりとか、getsが改行文字で止まったりとか、もう完全に文字を意識してますね。

まぁそんな感じで、全然まとまらないですがCの文字まわりは設計が中途半端だなぁという話でした。