1

ここには、ビットセットを使用して多くの 1 ビット値を char に格納するコードがいくつかあります。

基本的

struct BITS_8 {
  char _1:1;
  (...)
  char _8:1;
}

今、私はこれらのビットの1つをパラメーターとして関数に渡そうとしていました

void func(char bit){
  if(bit){
    // do something
  }else{
    // do something else
  }
}

// and the call was
struct BITS_8 bits;
// all bits were set to 0 before
bits._7 = 1;
bits._8 = 0;
func(bits._8);

解決策は、関数を呼び出すときにビットを選択することでした:

func(bits._8 & 0x80);

//do somethingしかし、他のビットが設定されていたので、私は入り続けました。これが正しい動作なのか、コンパイラが壊れているのか疑問に思っていました。このコンパイラは、フリースケール ASIC 用のコードを生成する組み込みコンパイラです。

編集: 2 つの間違い: パラメータとそのビットの受け渡し。_8 は 0 でなければならず、そうでなければエラーは意味をなしません。

明確化

規格が課題について何を述べているかに興味があります

struct X{
   unsigned int k:6;
   unsigned int y:1;
   unsigned int z:1;
}

X x;
x.k = 0;
x.y = 1;
x.z = 0;

char t = X.y;

または?tを含む必要があります。1b00000010

4

4 に答える 4

0

Boolがunsignedintなどにtypedefされている場合、またはコンパイラがパックされた列挙型をサポートしていない場合に、charを使用してフラグを格納する理由がわかります。マクロを使用していくつかの「フラグ」を設定できます(以下の場所の値に基づいて名前を付けましたが、意味する名前を付ける方が理にかなっています)8つのフラグでは不十分な場合は、sizeof(まで他のタイプに拡張できます。タイプ)*8フラグ。

/* if you cannot use a packed enum, you can try these macros 
 * in combination with bit operations on the "flags"
 * example printf output is: 1,1,6,4,1 
 * hopefully the example doesn't make it more confusing
 * if so see fvu's example */

#include <stdio.h> /* for printf */
#define ONE ((char) 1)
#define TWO (((char) 1)<<1)
#define FOUR (((char) 1)<<2)
#define EIGHT (((char) 1)<<3)
#define SIXTEEN (((char) 1)<<4)
#define THIRTYTWO (((char) 1)<<5)
#define SIXTYFOUR (((char) 1)<<6)
#define ONETWENTYEIGHT (((char) 1)<<7)

int main(void){
printf("%d,%d,%d,%d,%d\n",ONE & ONE, ONE | ONE, TWO | 6, FOUR & 6, sizeof(ONE));
}
于 2012-07-04T06:19:59.237 に答える
0

わかりました、それはコンパイラのバグでした。私はコンパイラを作成した人々に手紙を書き、彼らはそれを確認しました。インライン関数を持つビットフィールドがある場合にのみ発生します。

彼らの推奨する解決策は(パッチを待ちたくない場合)です

func((char)bits._8));

他の答えは、正しい動作について正しいです。それでも、これは私の問題に対する答えであるため、これを答えとしてマークしています。

于 2012-07-04T14:32:15.533 に答える
0

1ビットのcharを1に設定できるとは思いません。その1ビットは、署名されているかどうかを判断するために残っているため、 と の差になります。0-1

必要なのは、unsigned charこの署名ビットを非表示にする です。次に、1と0のみを使用できます。

于 2012-07-03T16:03:03.440 に答える
0

何年にもわたって、私はこれらの特定のコンパイラに関しては少し疑念を抱くようになりました.C標準の細かい点を説明できるものについての彼らの解釈はあまり良くありません. そのような場合、より実用的なアプローチは、狂気を回避し、仕事を成し遂げるのに役立ちます. この場合、これが意味することは、コンパイラが合理的に動作していない場合 (gcc の動作とはまったく異なる動作として定義できます)、少し助けになるということです。

たとえば、次のように func を変更できます。

void func(char bit){
  if(bit & 1){ // mask off everything that's none of its business
    // do something
  }else{
    // do something else
  }
}

そして、アドオンの質問について: t には 1 が含まれている必要があります。変数は 1 ビット幅しかないため、10 個のバイナリを含めることはできません。

C99 の最終公開ドラフトからの読み物

パラグラフ 6.7.2.1

4 ビットフィールドは、_Bool、signed int、unsigned int、またはその他の実装定義型の修飾または非修飾バージョンである型を持つものとします。

(これは、コンパイラが少なくとも2番目の例を正しく処理する必要があることを意味します)および

9 ビットフィールドは、指定されたビット数で構成される符号付きまたは符号なしの整数型として解釈されます。フィールドは、保存された値と等しくなります。

あなたのコンパイラは、ビットフィールドがかなり重要な機能である組み込み使用を目的としているため、ビットフィールドが実装されていると主張する場合、それらの実装が正しいと期待しています。

于 2012-07-03T16:27:27.263 に答える