- ベストアンサー
C言語のビットフィールドについて
- C言語のビットフィールドについて質問があります。ビットフィールドの宣言にはunsigned int型を使用することが推奨されていますが、他の型を使用することはできないのでしょうか。
- unsigned charなどの型を使用してもプログラムは動作しますが、なぜ推奨されていないのか、特に問題はあるのか疑問です。
- ビットフィールドの宣言にはunsigned int型が一般的に使用されますが、他の型を使用することも可能です。ただし、unsigned int型以外の型を使用する場合は注意が必要です。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
まず、C言語はアセンブラの替わりを務めるために産まれてきたという事を思い出していただきたい。 つまり、ビットフィールドを操作するのはCPUであり、CPUにとって何が楽か、速いかを考えてあげねばならん。 32ビットCPUにとってもっとも見易いのは当然32ビット長のデータであり、メモリ使用効率についても同じ事が言える。unsigned charを処理するのとunsigned intを処理するのでは少なくともほぼ同等、おそらくだがかなりの確率(ほぼ100%)でunsigned intの方が速い上にメモリ効率上も優れている。であればunsigned charを選ぶ理由はあるだろうか? そもそもcharとintって何やねんというところから話をしておこう。charとintの定義を調べると、charは「対象のマシンで一文字を現すのに適した長さ」、intは「対象のマシンで処理するのに適した長さ」とある。世の中にはcharが6ビットであるCコンパイラも、intが36ビットであるCコンパイラもある。なので、なぜintか、ではなく、そういう役割を担うためにintが定義された、と言うべきだろう。
その他の回答 (6)
- colder
- ベストアンサー率43% (30/69)
ビットフィールドに指定できるのはunsigned intと signed intだけ(C99以降なら_Boolも可)と規格に定められています。 それ以外の型をビットフィールドに指定するのは処理系の勝手な独自拡張で、 コンパイラによっては、コンパイル出来ません。
- Tacosan
- ベストアンサー率23% (3656/15482)
C と C++ とではビットフィールド周りが微妙に非互換だったりするので注意が必要です>#5. ただし int count:4; と書いたからと言って必ずしも「符号付き」とはならない点は C も C++ も違わなかったりします.
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
ビットフィールドで指定する型は、「整数型」であれば良いので、unsigned char でも、問題ないようです。 語長については、まず、ここのビットフィールドの長さは、: 以降で指定した長さなので、unsigned int でも、unsigned char でも、同じです。 ただ、処理系によっては struct{ unsigned int bit0:1; unsigned int bit1:1; : unsigned int bit7:1; }bits; だと、(bit0 から bit7 まであるとして)bits 全体のサイズを unsigned int と同じサイズにして、 ただ、処理系によっては struct{ unsigned char bit0:1; unsigned char bit1:1; : unsigned char bit7:1; }bits; だと、bits 全体のサイズを、unsigned char と同じサイズにするということもあるようで、たしかに、unsigned char で指定した方が、全体のサイズは小さくなるというケースはありそうです。 ただ、unsigned int を使っても、unsigned char を使っても、動作に差がないので、「普通は、(よく使われる)unsigned int で指定する」と言うことなのではないかと思います。 ※また、わずかにメモリサイズを抑えることと引き替えに、読んだ人を「何これ? どういう意図で?」と思わせるような書き方は、避けた方が無難ではあります。 さて、話題を変えて、ビットフィールドの使われ方についてです。 ビットフィールドは、次のいずれかの目的で使われます。 1)本当に、「ビットごと」の操作が必要なケース 現在のシステムには、「フラグ」というものがよく使用されます。 たとえば、 http://docs.oracle.com/cd/E19205-01/821-2495/bkaki/index.html の 13.4.1.1 オープンモード で、 enum open_mode {binary=0, in=1, out=2, ate=4, app=8, trunc=0x10, nocreate=0x20, noreplace=0x40}; という定義がありますが、これは、たとえば、 struct{ unsigned int in:1; // bit 0 unsigned int out:1; // bit 1 unsigned int ate:1; // bit 2 unsigned int app:1; // bit 3 unsigned int trunc:1; // bit 4; unsigned int nocreate:1: // bit 5; unsigned int noreplace:1; // bit 6: } というビットフィールドを前提とした定義です。 この用途では、フィールド全体の大きさも予め決まっているので、unsigned char を使って、メモリ幅を小さくするということも、不要かとは思います。 2)メモリの節約のために、「語長の短いデータ」として使う場合 これは、本当にデータメモリの節約をしなければならない場面で使われます。 組み込み用といわれる、小さな家電などの用途では今でも使われる場面はゼロではありません。 ビットフィールドで、メモリは省略できても、余計な処理がいる(一発で代入とかできないので)プログラムサイズが大きくなるという話もあるのですが、データメモリ(RAMです)がプログラムメモリより高価であったりするときにやむなく使われることもあります。 この用途では、 int count:4; のように、符号付き整数のビットフィールドも出てきます。 この用途では、unsigned char でフィールド全体のサイズを小さくするというのは、ありかもしれません。
- Tacosan
- ベストアンサー率23% (3656/15482)
それはそのテキストを書いた人間に聞くべきじゃないかね. まあ, 汎用性がなくなっちゃうんだけど.
- 松延 英樹(@maznobu)
- ベストアンサー率46% (80/171)
なぜint型なのかというと、C言語が開発された時代背景が関わっています。 C言語が作られた当初は、16ビット幅のデータバスを持つプロセッサが多くを占めていました。 そのために標準で使う型をint型として、そのint型を16ビット幅の標準としました。 一方のchar型は、英文化の上で出来た文字を表すための型で、8ビットあれば十分足りるので8ビット幅なのですが、16ビット幅のデータバスを扱うCPU上では、8ビット単位で処理するとデータ領域のアドレッシングを行う上での都合が悪いのです。 具体的には、C言語コンパイラではビットフィールドを扱うとき、低レベル言語である機械語上の命令サイクルで、すべてのデータは常に16ビット単位で扱われ、あるデータの次のアドレスは2バイト分先のアドレスになります。そこにその半分の8ビットデータがあると、プロセッサは内部的には16ビット単位でしか処理できないため、残りの8ビットは使いませんので、常に8ビット分の、態々残りのビットを空白で埋めるバウンダリングという処理をするのです。この処理には、その余白を埋めるための命令の分だけプロセッサのサイクルを余分に使い、結果的に8ビットで処理するよりも、16ビット単位で行ったほうが処理が早かったために、C言語上もバイト演算やビット演算にint型を使うようになったのです。
- lv4u
- ベストアンサー率27% (1862/6715)
>>ここで質問は,unsigned charなどの型は推奨されない理由があるのか,ということです。 ビット処理を行うプログラムを書くとき、ビットフィールドでなく、unsigned charを使うと、プログラムの記述が面倒で分かりずらくなると思いますよ。 もちろん、「そんなのたいした問題ではない」というプログラムなら、unsigned charで記述されればいいと思います。
お礼
みなさんご回答ありがとうございました。 おかげさまで,理解が深まったと思います。 CPUの処理速度や効率の話は、考えになかったです。 規格上きまっている,という話も参考になりました。 ベストアンサーはすばやく回答してくださった方にします。