ビットフラグを扱う時に、ビットフィールドを使用したほうが、
ビット演算子を組み合わせなくても出来るので簡単でいいと思うのですが、
ビット演算子を使うメリット、デメリット。またビットフィールドのメリット、デメリットを
あったら教えて頂きたいと思います。
使いますか?と聞かれたら、俺は使いません。
夢幻さんが使いたいのでしたらご自由にどうぞ。
ただ、Windows API がビットフラグを使ってるので、それとの一貫性を取るためにビッ
トフラグにすることはあるんじゃないでしょうか。
ビットフィールドがあまり使われないことの理由としては、そのくらいしか思いつきま
せんでした。
σ(^^)はビットフィールドは使っていません。
昔はメモリ資産が厳しかったのでメモリ節約のためにビットフィールドを使う事が
あったかもしれませんが、今はメモリ資産は結構ゆとりがあるので、ビットフィールド
を使う必要はないと思います。
聞いた話ですが、ビットフィールドを使うと、演算するとき、ビットの位置を特定する
ためにわざわざ計算しているそうで、今となってはメモリサイズよりは速度優先かな、
と思っています。
それよりも、これが一番重要なことですが、ビットフィールドを使わない方が可読性が
上がると思います。
# 無論、例外もあって、ハードウェア系など、メモリ資産が厳しいところなどで、
# メモリ節約を優先するようなコーディングを要求される場合は別ですが。
まとめ。
▼ビットフラグ
・メリット:可読性。アクセスが速い(?)
・デメリット:メモリが多く必要。
▼ビットフィールド
・メリット:メモリが節約できる。
・デメリット:可読性が下がる事も。アクセスが遅い(?)
※補足
・可読性については好みかもしれません。
・また、ビットフィールドと同じような事をビット演算をせずともunionを使えば、
ビットフラグ式で行なう事もできます。
あー、いまさら思いついたんだけど
ビットフィールドだとマスク演算が面倒だぁね。
横槍すみません。
ビットフィールドって
boolみたいに処理系依存の型に1か0しか入らないようにした物の事を
言うのではなかったでしょうか。
(残りのビットは無駄になるけど if(XX != TRUE)みたいな誤動作を防げる。)
ビットフラグとは例えば32bitの型を32個のフラグとして扱って、
AND演算で任意の桁が1か0かを取りです物という認識なんですが...
そう考えるとRAPTさんの考え方の正反対になるんですけど...
認識違っているのでしょうか。
ビットフィールドってのは
struct
{
unsigned long bit0 : 1;
unsigned long bit1 : 1;
unsigned long bit2 : 1;
// 中略
unsigned long bit31 : 1;
}
bits1;
bits2.bit28 = 0;
bits1.bit31 = 1;
こんな風に書くと、32 ビットを 1 ビットずつ扱えるというシロモノです。
struct
{
unsigned long low8 : 8;
unsigned long high24 : 24;
}
bits2;
のように、数ビットずつ扱うこともできますし
struct
{
unsigned short lowbyte : 8;
unsigned short highbyte : 8;
unsigned char bit0 : 1;
unsigned char bit1 : 1;
// 残り 6 ビットは無駄
}
bits3;
32 ビットに限った話でもないし、無駄な領域があっても構いません。
ビットフィールドの型には、int, signed int, unsigned int, および_Boolしか使えま
せん。
といっても、ほとんどのコンパイラではcharやlongなども使えてしまいますが...
あや、これは失敬。
やっぱり一度、規格書読まなきゃダメだなぁ…
本当に横槍ですみませんが、参考になりました。
手持ちの本に説明がある物が無くて、たまたま何かのソースをみて思い違いをして
いました。(その中では1bitしか使っていなかったのかなあ。)
ありがとうございました。> シャノンさん
大変失礼しました。 > 夢幻さん
返信遅くなってすみませんでした
ある変数を
struct
{
UINT m_uCoordX : 8; //X座標
UINT m_uCoordY : 8; //Y座標
UINT m_uAngle : 8; //角度
UINT m_uFlag1 : 1; //フラグ1
UINT m_uFlag2 : 1; //フラグ2
UINT m_uFlag3 : 1; //フラグ3
} v;
のようにすれば、
v.m_uCoordY = 50;
v_m_uFlag1 = 1;
のように書け、必要以上の代入を防げますし、解りやすいですが
普通の変数では
v = (v & 0xffff00ff) | (50 << 8);
v = (v & 0xfeffffff) | (1 << 24);
のように書かなければならないと思います。
これが面倒だったのでそれぞれのメリット、デメリットはなんなのか、
皆さんはどうしているのか、という質問だったのですが
皆さんはあまり使っていないようですね。
しかし、ビットフィールドでマスク演算というのはなんなんでしょうか?
うぅむ…なんかよく考えずに発言してしまったラシイ
そもそもビットフィールドを使えばマスクの必要ないんですねぇ…
vを
struct {
unsigned char m_uCoordX;
unsigned char m_uCoordY;
unsigned char m_uAngle;
unsigned char m_uFlags;
} v;
と定義すれば,
> v.m_uCoordY = 50;
は当然通りますし,
> v_m_uFlag1 = 1;
は
v.m_uFlags |= 1;
で済みます。
フラグであればビット演算,加算等を行うのであればbit-fieldでない型を使うので,
bit-fieldは使いませんね。
フラグの初期設定が非常に面倒なことになりますし。
v.m_uFlags = 1 | 2;
が,
v.m_uFlag1 = 1;
v.m_uFlag2 = 1;
v.m_uFlag3 = 0;
のようになってしまうのは面倒なだけです。
ビットフィールドは、Bitに名前をつけることでソースコードの可読性を
容易にし、コードの変更を容易にしますが、処理速度が低下するという認識
をもっています。
ただ、速度については、最近のコンパイラを評価していませんので
変わらないかもしれません。
1Chipマイコンでメモリが厳しいときや、通信データなど、データ量を
減らしたい場合にビット変数を使用していますが、
ビットフィールドとするかビット列のままにするかは
名前をつける必要があるかないかで決めています。
> ただ、速度については、最近のコンパイラを評価していませんので
> 変わらないかもしれません。
シフト・論理演算を使って同じことを実現する場合と比べれば、速度低下は特にないは
ずです。
効率が悪くなるのは、ビットフィールドの値を(まじめに)取り出す場合で、符号拡張
などの操作が入るために大きく遅いコードが展開されます。真偽の判定だけならそれほ
ど効率は低下しません。
> 1Chipマイコンでメモリが厳しいときや、通信データなど、データ量を
> 減らしたい場合にビット変数を使用していますが、
1チップマイコンの場合には、RAMは確かに節約できますがROMを著しく浪費します。ま
た、制御レジスタへのアクセスにビットフィールドを使うのも色々と問題があります。
通信データの場合は確かにデータ量が減るのですが、ビットフィールドの展開のされか
たは処理系によって大きく異なるので、厄介な問題が付いて回ります。
規格なのか実装なのかわかりませんが、ビットフィールドを使うと1ビットずつ消費す
るんですか?
たとえば、
struct
{
short onebit : 1;
}
s;
とした場合、消費されるのは1ビットだけなんでしょうか?
この場合、short だから2バイト、あるいは最適化されても1バイト消費されることに
なるのでは…?