char型でマイナスの値なんか使わないのだから、全部unsigned charにすればいいんじゃないかと思うのですが、
char/unsigned charを何のために使い分けるのか教えてください。
事例:https://github.com/git/git/blob/master/cache.h
C の char 型は、基本的には「1バイト幅の整数型」です。整数型ですから、short や int 同様に、signed も unsigned も有る、ただそれだけの事です。
その名前から、多くの方が「思い込み」をしてしまっていますが、char 型は、文字専用の型ではありません。C において「文字」とは文字コード値という整数値であるに過ぎず、文字コード値を char 型領域に入れようが int 型領域に入れようが、何も問題はありません。
たとえば標準ライブラリ関数 getchar( ) の戻り値は int 型ですが、EOF やエラーでない限り、この int 型値には文字コード値が格納されるでしょう。
また、ワイド文字(コード値)は、char 型ではなく wchar_t 型という整数型で扱われます。C は、あくまで、「文字コード値を整数型で扱う」だけなのです。
ならば、「全て int で良いではないか」と考えられるかも知れません。確かに、ほとんど全てのプログラムは、int 型だけで記述可能です(アドレス値も、大抵の場合は int 幅の整数値である)。
整数型としての char の存在意義は、「ビット幅が必ず1バイトである事が規格上保証されている」という事です。
int は、何バイト幅であるかが処理系定義です。つまり、int 型の sizeof に依存するプログラムは、移植性が失われています。対して char の場合は、sizeof( char ) が必ず1になるので、型のバイト幅に関して移植性を重視する場合、char を基準にしたプログラムを書く事になります。
このような、「どこでも1バイト幅」という char 型の性質は、ポインタ演算を多用する C の文字列プログラミングにおいて、非常に都合が良いものです。int ポインタ型に +1 した際、何バイト進むのかは処理系定義ですが、char ポインタ型ならば必ず1バイトだけ進むからです。
確かに、実務レベルのプログラムでchar でマイナスを使うことはまずないですね。
これは、言語仕様で仕方ないと思って下さい。
ありがとうございます。
実務ではないんですね。
ではなぜGitではchar型が使われているんでしょう・・
とても似た疑問を最近持っていたのですが、符号付きにも意義があることに気付きました。
(僕が疑問を持っていたのはcharではなく日付時刻連番についてですが)
ASCIIが0~127しか使っていないのは、符号つき8ビットで表せるようにです。なぜ使いもしない負の値も表現できるようにしたいか?
それは、文字同士の引き算をした結果がかならず定義域内に収まるからです。
文字同士の引き算はありますよね? 大文字を小文字に変換するなんていうイディオムでも c - 'A' + 'a' なんて書きます。
おお!
文字同士の引き算・・・
そういえばGit内部で文字同士の演算をしている箇所が何か所かありました。
もしかしたらそれかもしれません。
C の char 型は、基本的には「1バイト幅の整数型」です。整数型ですから、short や int 同様に、signed も unsigned も有る、ただそれだけの事です。
その名前から、多くの方が「思い込み」をしてしまっていますが、char 型は、文字専用の型ではありません。C において「文字」とは文字コード値という整数値であるに過ぎず、文字コード値を char 型領域に入れようが int 型領域に入れようが、何も問題はありません。
たとえば標準ライブラリ関数 getchar( ) の戻り値は int 型ですが、EOF やエラーでない限り、この int 型値には文字コード値が格納されるでしょう。
また、ワイド文字(コード値)は、char 型ではなく wchar_t 型という整数型で扱われます。C は、あくまで、「文字コード値を整数型で扱う」だけなのです。
ならば、「全て int で良いではないか」と考えられるかも知れません。確かに、ほとんど全てのプログラムは、int 型だけで記述可能です(アドレス値も、大抵の場合は int 幅の整数値である)。
整数型としての char の存在意義は、「ビット幅が必ず1バイトである事が規格上保証されている」という事です。
int は、何バイト幅であるかが処理系定義です。つまり、int 型の sizeof に依存するプログラムは、移植性が失われています。対して char の場合は、sizeof( char ) が必ず1になるので、型のバイト幅に関して移植性を重視する場合、char を基準にしたプログラムを書く事になります。
このような、「どこでも1バイト幅」という char 型の性質は、ポインタ演算を多用する C の文字列プログラミングにおいて、非常に都合が良いものです。int ポインタ型に +1 した際、何バイト進むのかは処理系定義ですが、char ポインタ型ならば必ず1バイトだけ進むからです。
>しおり さん
上記文章には、おっしゃられるような前提は入っていないと思うのですが、どこがそうであるのか教えていただけないでしょうか。
・char 型は、基本的には「1バイト幅の整数型」である。それだけのこと。
・整数型としての char の存在意義は、「ビット幅が必ず1バイトである事が規格上保証されている」という事
なるほど、よくわかりました。
ありがとうございます!
まぁ、普通は使う事は無いけど、char 型はあくまで、大きさ 1 byte の整数型なので、整数型である以上、符号付き、符号なしの両方を用意する必要がある、といったところでしょう。で、他のサイズの整数型(int や long)に合わせると、signed の方がデフォルトで、故に char 型は符号付きになる。
絶対に符号付きの char 型が不必要か、となると、組み込み系でメモリサイズがシビアだったり、制御機器とのデータのやり取りで、低い転送レートのバスを使ってシビアなタイミングの処理をする、といった時に、絶対に符号付き1バイト整数を使わない、とは言えないかなぁ、と。
例えば、あるセンサーの値が 0~10 の整数値で、センサー異常の時はマイナスの値、といった時に、符号付き char 型として取り扱えば、値がマイナスかどうかで異常を判断できます。まぁ、ビット演算で再上位ビットが立っている場合は異常、でも良いのですが、-1 の時はこういう異常、-2 の時はこういう異常、といった時は、符号付き整数として取り扱えた方が便利かな、と。
C 言語は元々、OS を記述するための言語として生まれているので、基本的にアセンブラの代わりをするためのもの、という位置づけがあります。で、ASCII コードで事が足りる時代には、1 byte の整数が文字を格納するのに調度良かったから「char 型」なんて名前が付いていますが、実態はあくまでも「整数型」なんで、他の整数型に合わせて、符号付き、符号なしの両方が用意され、デフォルトは符号付き、という事になると思います。
・charの実体はあくまで「整数型」である。整数型だから符号付符号なしの2通りの型がある。
・組込みの世界ではchar型のニーズはちゃんとある
なるほど。
C言語では、元々、整数型の変数は、共通して、最上位ビットで符号を表す仕様なので、char型も、その例外ではありません。
しかし、負数は必要ないので、その代わりに正数をもっと増やしてほしいという要求に答えるために「符号修飾」という機能を用意したようです。まぁ、結局、仕様なんでしょうね。(^_^;
ちなみに、比較的新しい言語のJavaでは、0と正の数だけです。(^_^;
そういえば、Cにもコンパイラオプションがありました。英語圏の人には、unsigned charは、あまり必要ないみたいですね。(^_^;
●/J (既定の char 型の unsigned への変更)
ANSI C と C++ では、char 型の特別な実装は必要ありません。/J オプションが必要になるのは、最終的に英語以外の言語に翻訳する文字データを扱う場合です。
http://bit.ly/19OlCX4
※参考URL
●C言語講座:整数の内部表現
http://www1.cts.ne.jp/~clab/hsample/Bit/Bit3.html
ありがとうございます。
そういえば、Dosのころ、Cでメモリが足らなくなって苦労したことがありました。(^_^;
intの巨大配列は無理でもcharならとれたりすることがありました。
と使い分けていると思います。
多くの文字を扱うようになった現在では、文字も符号なしの方が都合が良いと思いますが、標準/非標準ライブラリの文字列を扱う関数がchar *型を使っているために、今更unsigned char型には変えられないのだと思います。
# バイト列を格納するのにchar *型を使うと汎整数拡張ではまることがあるので、unsigned char *を使いたいですね。
・多くの文字を扱うようになった現在では、文字も符号なしの方が都合が良いが、ライブラリがchar *型固定なのでいまさら変更できない
なるほど。
>しおり さん
2013/10/16 07:05:24上記文章には、おっしゃられるような前提は入っていないと思うのですが、どこがそうであるのか教えていただけないでしょうか。
・char 型は、基本的には「1バイト幅の整数型」である。それだけのこと。
2013/10/20 23:40:12・整数型としての char の存在意義は、「ビット幅が必ず1バイトである事が規格上保証されている」という事
なるほど、よくわかりました。
ありがとうございます!