C言語でchar型の存在意義がわかりません。


char型でマイナスの値なんか使わないのだから、全部unsigned charにすればいいんじゃないかと思うのですが、
char/unsigned charを何のために使い分けるのか教えてください。

事例:https://github.com/git/git/blob/master/cache.h

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2013/10/20 23:47:14
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:khurata No.3

回答回数35ベストアンサー獲得回数10

ポイント50pt

 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バイトだけ進むからです。

id:khurata

>しおり さん
 上記文章には、おっしゃられるような前提は入っていないと思うのですが、どこがそうであるのか教えていただけないでしょうか。

2013/10/16 07:05:24
id:DQNEO

・char 型は、基本的には「1バイト幅の整数型」である。それだけのこと。
・整数型としての char の存在意義は、「ビット幅が必ず1バイトである事が規格上保証されている」という事

なるほど、よくわかりました。
ありがとうございます!

2013/10/20 23:40:12

その他の回答6件)

id:Vacuum No.1

回答回数55ベストアンサー獲得回数4スマートフォンから投稿

確かに、実務レベルのプログラムでchar でマイナスを使うことはまずないですね。
これは、言語仕様で仕方ないと思って下さい。

id:DQNEO

ありがとうございます。
実務ではないんですね。
ではなぜGitではchar型が使われているんでしょう・・

2013/10/15 09:08:57
id:Sampo No.2

回答回数556ベストアンサー獲得回数104

ポイント10pt

とても似た疑問を最近持っていたのですが、符号付きにも意義があることに気付きました。
(僕が疑問を持っていたのはcharではなく日付時刻連番についてですが)

ASCIIが0~127しか使っていないのは、符号つき8ビットで表せるようにです。なぜ使いもしない負の値も表現できるようにしたいか?

それは、文字同士の引き算をした結果がかならず定義域内に収まるからです。

文字同士の引き算はありますよね? 大文字を小文字に変換するなんていうイディオムでも c - 'A' + 'a' なんて書きます。

id:DQNEO

おお!
文字同士の引き算・・・

そういえばGit内部で文字同士の演算をしている箇所が何か所かありました。

もしかしたらそれかもしれません。

2013/10/15 09:21:27
id:khurata No.3

回答回数35ベストアンサー獲得回数10ここでベストアンサー

ポイント50pt

 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バイトだけ進むからです。

id:khurata

>しおり さん
 上記文章には、おっしゃられるような前提は入っていないと思うのですが、どこがそうであるのか教えていただけないでしょうか。

2013/10/16 07:05:24
id:DQNEO

・char 型は、基本的には「1バイト幅の整数型」である。それだけのこと。
・整数型としての char の存在意義は、「ビット幅が必ず1バイトである事が規格上保証されている」という事

なるほど、よくわかりました。
ありがとうございます!

2013/10/20 23:40:12
id:JULY No.4

回答回数966ベストアンサー獲得回数247

ポイント20pt

まぁ、普通は使う事は無いけど、char 型はあくまで、大きさ 1 byte の整数型なので、整数型である以上、符号付き、符号なしの両方を用意する必要がある、といったところでしょう。で、他のサイズの整数型(int や long)に合わせると、signed の方がデフォルトで、故に char 型は符号付きになる。

絶対に符号付きの char 型が不必要か、となると、組み込み系でメモリサイズがシビアだったり、制御機器とのデータのやり取りで、低い転送レートのバスを使ってシビアなタイミングの処理をする、といった時に、絶対に符号付き1バイト整数を使わない、とは言えないかなぁ、と。

例えば、あるセンサーの値が 0~10 の整数値で、センサー異常の時はマイナスの値、といった時に、符号付き char 型として取り扱えば、値がマイナスかどうかで異常を判断できます。まぁ、ビット演算で再上位ビットが立っている場合は異常、でも良いのですが、-1 の時はこういう異常、-2 の時はこういう異常、といった時は、符号付き整数として取り扱えた方が便利かな、と。

C 言語は元々、OS を記述するための言語として生まれているので、基本的にアセンブラの代わりをするためのもの、という位置づけがあります。で、ASCII コードで事が足りる時代には、1 byte の整数が文字を格納するのに調度良かったから「char 型」なんて名前が付いていますが、実態はあくまでも「整数型」なんで、他の整数型に合わせて、符号付き、符号なしの両方が用意され、デフォルトは符号付き、という事になると思います。

id:DQNEO

・charの実体はあくまで「整数型」である。整数型だから符号付符号なしの2通りの型がある。
・組込みの世界ではchar型のニーズはちゃんとある

なるほど。

2013/10/20 23:41:57
id:rsc96074 No.5

回答回数4505ベストアンサー獲得回数438

ポイント10pt

 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

id:DQNEO

ありがとうございます。

2013/10/20 23:42:23
id:rsc96074

そういえば、Dosのころ、Cでメモリが足らなくなって苦労したことがありました。(^_^;
intの巨大配列は無理でもcharならとれたりすることがありました。

2013/10/20 23:50:43
id:Bookmarker No.6

回答回数191ベストアンサー獲得回数34

ポイント10pt
  • 文字を格納する場合はchar型
  • 小さい整数を格納する場合はunsigned char/signed char型

と使い分けていると思います。
多くの文字を扱うようになった現在では、文字も符号なしの方が都合が良いと思いますが、標準/非標準ライブラリの文字列を扱う関数がchar *型を使っているために、今更unsigned char型には変えられないのだと思います。

# バイト列を格納するのにchar *型を使うと汎整数拡張ではまることがあるので、unsigned char *を使いたいですね。

id:DQNEO

・多くの文字を扱うようになった現在では、文字も符号なしの方が都合が良いが、ライブラリがchar *型固定なのでいまさら変更できない

なるほど。

2013/10/20 23:43:09
id:j9R No.7

回答回数10ベストアンサー獲得回数2

組み込み系で下記を見たことあるのでひっそりと需要があるのだと思われます。

typedef signed char int8_t;

id:DQNEO

組込み系では需要があると。

2013/10/20 23:43:27
  • id:Yoshiya
    C言語が誕生したのは1972年です。
    その頃、C言語が動くコンピュータはUNIXしかなく、UNIXのアスキーコードは0x00~0x7f(十進数で127)の範囲で使用していました。
    つまり、文字型(char)で0x80より大きい数字は必要なかったのです。
    なので、char型の数値範囲を-128~127にしたのだと思います。

    http://okuyama.mt.tama.hosei.ac.jp/unix/C/slide95.html
    ASCIIチャート(ASCIIコード表)・法政大学 奥山研究室
  • id:Bookmarker
    みんなchar型は符号付きだという前提で回答してますが、処理系定義ですよ。
    http://www.kijineko.co.jp/tech/superstitions/char-is-signed.html
  • id:DQNEO
    ・当時は 127までの値で十分だった
    ・charのデフォルトがsignedであるかどうかは処理系次第

    コメントありがとうございます。
  • id:DQNEO
    自己レスです。

    http://funini.com/kei/c/char.shtml

    こちらの記事を読んだら理解が深まりました。
    ありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません