13


2

C / C ++ビットフィールドとビット単位の演算子を比較してビットを抜き出しますが、どちらがより速く、より良く、より移植性がありますか?

この方法でバイトにいくつかのビットをパックする必要があります。

struct
{
  char bit0: 1;
  char bit1: 1;
} a;

if( a.bit1 ) /* etc */

or:

if( a & 0x2 ) /* etc */

ソースコードの明快さから、ビットフィールドがきれいであることは私にはかなり明白です。 しかし、どのオプションが速いですか? 速度の差はあってもそれほど大きくないことはわかっていますが、いずれかを使用できるので、速度が速いほど優れています。 +一方、私は、ビットフィールドがプラットフォーム間でビットを同じ順序で配置することを保証されていないことを読んでおり、コードを移植可能にしたいと考えています。

注:「プロフィール」に答えるつもりなら大丈夫ですが、私は怠け者なので、誰かがすでに答えを持っている場合は、はるかに良いです。 +コードが間違っている可能性があります。必要に応じて修正できますが、この質問のポイントを覚えておいてください。

7 Answer


12


ビットフィールドを適切に使用すると、コードがより明確になります。 ビットフィールドはスペース節約デバイスとしてのみ使用します。 私がそれらを使用しているのを見た1つの一般的な場所はコンパイラです:多くの場合、タイプまたはシンボル情報は多くのtrue / falseフラグで構成されています。 典型的なプログラムでは、コンパイル時にこれらのノードが何千も作成されるため、ビットフィールドは理想的です。

一般的な組み込みプログラミングジョブ、つまりデバイスレジスタの読み取りと書き込みには、ビットフィールドを使用しません。 ここでシフトとマスクを使用することをお勧めします。これは、ドキュメントで必要とされているビットを正確に取得し、ビットフィールドのさまざまなコンパイラ実装の違いを心配する必要がないためです。

速度に関しては、優れたコンパイラーは、マスキングと同じビットフィールドに対して同じコードを提供します。


7


移植性を最大限に高めるために、2番目の例を優先的に使用します。 ニール・バターワースが指摘したように、ビットフィールドの使用はネイティブプロセッサ専用です。 OK、これについて考えてください。Intelのx86が明日廃業した場合、コードはスタックします。つまり、RISCチップなどの別のプロセッサ用にビットフィールドを再実装する必要があります。

大きな画像を見て、OpenBSDが1つのコードベースを使用して多くのプラットフォームにBSDシステムをどのように移植したのかを尋ねる必要がありますか? OK、それは少し上で、議論の余地があり主観的ですが、現実的に言えば、コードを別のプラットフォームに移植したい場合は、質問で使用した2番目の例を使用してそれを行う方法を認めます。

それだけでなく、さまざまなプラットフォームのコンパイラは、コンパイラがオンになっているプロセッサのビットフィールドを整列させる独自のパディング方法を持っています。 さらに、プロセッサのエンディアンについてはどうですか?

魔法の弾丸としてビットフィールドに頼らないでください。 プロセッサの速度が必要で、その速度が固定される場合、つまり 移植するつもりはないので、自由にビットフィールドを使用してください。 * 両方は持てません! *


6


Cビットフィールドは、未知の理由で、発明された瞬間から死んでいました。 人々はそれらを好まず、代わりにビット演算子を使用しました。 他の開発者がCビットフィールドコードを理解しないことを期待する必要があります。

どちらが速いかに関しては、無関係です。 最適化コンパイラ(実質的にすべてを意味する)は、どの表記法でもコードが同じことをするようにします。 Cプログラマーの一般的な誤解は、コンパイラがキーワードを検索してアセンブリに置き換えるだけだということです。 最新のコンパイラは、ソースコードを達成するための青写真として使用し、しばしば非常に異なって見えるが意図した結果を達成するコードを出力します。


5


最初の式は明示的であり、2番目の式の速度にかかわらず、構造体を変更すると2番目の式が間違っている可能性があるため、エラーが発生しやすくなります。

最初のものを使用してください。


4


移植性が必要な場合は、ビットフィールドを避けてください。 また、特定のコードのパフォーマンスに関心がある場合は、独自のテストを作成することに代わるものはありません。 ビットフィールドは、プロセッサの内部でビット単位の命令を使用することに注意してください。


1


Cプログラマーは、ビットマスクと論理演算を使用して各ビットの値を推測する2番目のオプションに向かう傾向があると思います。 コードに16進値が散在するのではなく、列挙がセットアップされるか、通常、より複雑な操作が関係する場合は、特定のビットを取得/設定するマクロが設定されます。 グレープバインで聞いたところによると、構造体で実装されたビットフィールドは遅いということです。


1


「移植性のないビットフィールド」ではあまり読みません。 実装定義であるビットフィールドには、2つの側面があります:符号付きとレイアウト、および1つの不特定なもの:それらがパックされる割り当てユニットのアライメント。 パッキング効果が他に何も必要ない場合、それらを使用すると、未指定のプロパティを持つ関数呼び出しと同じくらい移植性があります(必要に応じて明示的に `signed`キーワードを指定した場合)。

パフォーマンスに関しては、プロファイルが得られる最良の答えです。 完璧な世界では、2つの文章に違いはありません。 実際には、いくつかの可能性がありますが、一方の方向には多くの理由が考えられます。 そして、それはコンテキストに非常に敏感である可能性があります(たとえば、符号なしと署名付きの論理的に意味のない違い)ので、コンテキストで測定してください…​

まとめると、この違いはほとんどの場合、本当に選択できる場合のスタイルの違いです(つまり、 正確なレイアウトが重要な場合ではありません)。 これらの場合、それは最適化(サイズではなく、速度)であるため、最初にコードなしでコードを記述し、必要に応じて追加する傾向があります。 したがって、ビットフィールドは明らかな選択です(実行する変更は、結果を達成するための最小のものであり、すべての使用場所に広がるのではなく、定義の一意の場所に含まれます)。