はじめまして,今C言語を勉強中なのですが,
ビットフィールドの宣言について質問があります。
勉強に使用しているテキストでは,
ビットフィールドの宣言にはunsigned int型を使用すると書かれています(下記例参照)。
ここで質問は,unsigned charなどの型は推奨されない理由があるのか,ということです。
実際にunsigned char型で実行してもプログラムは動きますし,そちらのほうが語長も短くて済むのでいいような気がします。
テキストの書き方だと,他の型について言及していなかったので,なにか理由かあるのか,それとも特に問題ないのか,疑問に思っています。
わかる方いましたら,回答いただけると嬉しいです。
(ex)
struct{
unsigned int bit0:1;
unsigned int bit1:1;
:
unsigned int bit7:1;
}bits;
No.1ベストアンサー
- 回答日時:
まず、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が定義された、と言うべきだろう。
みなさんご回答ありがとうございました。
おかげさまで,理解が深まったと思います。
CPUの処理速度や効率の話は、考えになかったです。
規格上きまっている,という話も参考になりました。
ベストアンサーはすばやく回答してくださった方にします。
No.7
- 回答日時:
ビットフィールドに指定できるのはunsigned intと signed intだけ(C99以降なら_Boolも可)と規格に定められています。
それ以外の型をビットフィールドに指定するのは処理系の勝手な独自拡張で、
コンパイラによっては、コンパイル出来ません。
No.6
- 回答日時:
C と C++ とではビットフィールド周りが微妙に非互換だったりするので注意が必要です>#5.
ただし
int count:4;
と書いたからと言って必ずしも「符号付き」とはならない点は C も C++ も違わなかったりします.
No.5
- 回答日時:
ビットフィールドで指定する型は、「整数型」であれば良いので、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/bka …
の
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 でフィールド全体のサイズを小さくするというのは、ありかもしれません。
No.3
- 回答日時:
なぜint型なのかというと、C言語が開発された時代背景が関わっています。
C言語が作られた当初は、16ビット幅のデータバスを持つプロセッサが多くを占めていました。
そのために標準で使う型をint型として、そのint型を16ビット幅の標準としました。
一方のchar型は、英文化の上で出来た文字を表すための型で、8ビットあれば十分足りるので8ビット幅なのですが、16ビット幅のデータバスを扱うCPU上では、8ビット単位で処理するとデータ領域のアドレッシングを行う上での都合が悪いのです。
具体的には、C言語コンパイラではビットフィールドを扱うとき、低レベル言語である機械語上の命令サイクルで、すべてのデータは常に16ビット単位で扱われ、あるデータの次のアドレスは2バイト分先のアドレスになります。そこにその半分の8ビットデータがあると、プロセッサは内部的には16ビット単位でしか処理できないため、残りの8ビットは使いませんので、常に8ビット分の、態々残りのビットを空白で埋めるバウンダリングという処理をするのです。この処理には、その余白を埋めるための命令の分だけプロセッサのサイクルを余分に使い、結果的に8ビットで処理するよりも、16ビット単位で行ったほうが処理が早かったために、C言語上もバイト演算やビット演算にint型を使うようになったのです。
No.2
- 回答日時:
>>ここで質問は,unsigned charなどの型は推奨されない理由があるのか,ということです。
ビット処理を行うプログラムを書くとき、ビットフィールドでなく、unsigned charを使うと、プログラムの記述が面倒で分かりずらくなると思いますよ。
もちろん、「そんなのたいした問題ではない」というプログラムなら、unsigned charで記述されればいいと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語 共用体について コマンドライン引数で値を2つ入力したときに、argv[2]の値をUNI u1 4 2022/04/25 20:34
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# C++初心者です stirng 2 2022/09/20 20:43
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
c++ 文字列を入力して、一文字...
-
CStringをwchar_tに変換したい
-
charからLPTSTRへの変換方法
-
干支のプログラム
-
文字列から空白を取り除きたい...
-
配列をnビットシフトする
-
C言語のfor文です。 繰り返しの...
-
ファイル名である文字列からbas...
-
enumの記述について。
-
str系関数を使わずに二つの文字...
-
2曲同時再生するにはどうした...
-
atoi( ) の反対をやりたい
-
コンパイルエラー invalid ope...
-
MFCでのBITMAP作成について
-
ヘキサ表現が上手く行かない
-
double型の値をchar配列に変換...
-
C言語プログラミングについて(...
-
テキストデータをそのままバイ...
-
TCHAR文字列?の特定部分の数字...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
charでの計算?
-
C言語のfor文です。 繰り返しの...
-
charからLPTSTRへの変換方法
-
文字列から空白を取り除きたい...
-
C言語の入力した文字を反転させ...
-
'const char *' 型は 'char *' ...
-
配列をnビットシフトする
-
str系関数を使わずに二つの文字...
-
int main()の・・・
-
atoi( ) の反対をやりたい
-
c++ 文字列を入力して、一文字...
-
CStringをwchar_tに変換したい
-
switch文で文字を比較すること...
-
干支のプログラム
-
絶対パスからのファイル名の切...
-
3桁区切(コンマ)記号をつけ...
-
間接操作のレベルとは
-
間接参照のレベルが異なっています
-
【C言語】文字型と整数型の違い
おすすめ情報