17

私はCプログラムを書いています。charとしてアクセスできる変数が必要ですが、の特定のビットにもアクセスできます。このような組合が使えると思っていたのですが…

typedef union 
{
    unsigned char status;
    bit bits[8];
}DeviceStatus;

しかし、コンパイラはこれを好みません。どうやら、構造体でビットを使用することはできません。では、代わりに何ができますか?

4

6 に答える 6

29

もちろんですが、実際には構造体を使用してこのようなビットを定義する必要があります

typedef union
{
  struct
  {
    unsigned char bit1 : 1;
    unsigned char bit2 : 1;
    unsigned char bit3 : 1;
    unsigned char bit4 : 1;
    unsigned char bit5 : 1;
    unsigned char bit6 : 1;
    unsigned char bit7 : 1;
    unsigned char bit8 : 1;
  }u;
  unsigned char status;
}DeviceStatus;

次に、にアクセスできます。にDeviceStatus ds;アクセスできますds.u.bit1。また、一部のコンパイラでは、実際にはユニオン内に匿名構造を使用できるためds.bit1、typedefからuを省略した場合にのみアクセスできます。

于 2010-08-16T21:12:51.050 に答える
4

いくつかの可能性があります。1つは、ブール演算を使用してビットを取得することです。

int bit0 = 1;
int bit1 = 2;
int bit2 = 4;
int bit3 = 8;
int bit4 = 16;
int bit5 = 32;
int bit6 = 64;
int bit7 = 128;

if (status & bit1)
    // whatever...

もう1つは、ビットフィールドを使用することです。

struct bits { 
   unsigned bit0 : 1;
   unsigned bit1 : 1;
   unsigned bit2 : 1;
// ...
};

typedef union {
    unsigned char status;
    struct bits bits;
} status_byte;

some_status_byte.status = whatever;
if (status_byte.bits.bit2)
    // whatever...

1つ目は(少なくとも間違いなく)より移植性が高いですが、ステータスビットを扱っている場合、コードは少しでも移植性がない可能性があるため、あまり気にしないかもしれません...

于 2010-08-16T21:16:30.937 に答える
3

すでに述べたように、Cでは1バイトよりも小さいメモリをアドレス指定することはできません。マクロを記述します。

#define BIT(n) (1 << n)

それを使用してビットにアクセスします。そうすれば、アクセスしている構造のサイズに関係なく、アクセスは同じになります。コードは次のように記述します。

if (status & BIT(1)) {
   // Do something if bit 1 is set
} elseif (~status | BIT(2) {
   // Do something else if bit 2 is cleared
} else  {
   // Set bits 1 and 2
   status |= BIT(1) | BIT(2)
   // Clear bits 0 and 4
   status &= ~(BIT(0) | BIT(4))
   // Toggle bit 5 
   status ^= BIT(5)
}

これにより、()の代わりに[]を使用する提案されたシステムの近くにアクセスできます。

于 2010-08-16T21:30:20.813 に答える
2
typedef union
{
  unsigned char status;
  struct bitFields
  {
    _Bool bit0 : 1;
    _Bool bit1 : 1;
    _Bool bit2 : 1;
    _Bool bit3 : 1;
    _Bool bit4 : 1;
    _Bool bit5 : 1;
    _Bool bit6 : 1;
    _Bool bit7 : 1;
  } bits;
}DeviceStatus;
于 2010-08-16T21:13:48.350 に答える
0

Cでアドレス指定可能な最小単位は、常に1バイトです(charCで呼び出されます)。ビットに直接アクセスすることはできません。ビットにアクセスするための最も近い方法は、呼び出されるデータ型を定義し、bitpointerそのためのいくつかの関数またはマクロを定義することです。

#include <stdbool.h>

typedef struct bitpointer {
    unsigned char *pb; /* pointer to the byte */
    unsigned int bit; /* bit number inside the byte */
} bitpointer;

static inline bool bitpointer_isset(const bitpointer *bp) {
    return (bp->pb & (1 << bp->bit)) != 0;
}

static inline void bitpointer_set(const bitpointer *bp, bool value) {
    unsigned char shifted = (value ? 1 : 0) << bp->bit;
    unsigned char cleared = *bp->pb &~ (1 << bp->bit);
    *(bp->pb) = cleared | shifted;
}

ユニオンは、msb-to-lsbまたはlsb-to-msbのどちらで埋められるかは実装によって定義されるため、ユニオンには使用しないことをお勧めします(ISO C99、6.7.2.1p10を参照)。

于 2010-08-16T21:21:37.507 に答える
0

ユニオン内の構造体にビットを配置することでそれを行うことができますが、実装によっては機能する場合と機能しない場合があります。言語定義では、個別のビットがunsigned char;のビットと一致する順序は指定されていません。さらに悪いことに、ビットが(と重なることさえ保証されませんunsigned char(コンパイラは、単語の最上位側と最下位側に別々のビットを配置するunsigned charか、またはその逆を決定する場合があります)。

あなたの状況での通常のテクニックは、ビット演算を使用することです。ビットの意味にちなんで名付けられた定数を定義します。

#define FLAG_BUSY 0x01
#define FLAG_DATA_AVAILABLE 0x02
#define FLAG_TRANSMISSION_IN_PROGRESS 0x04
...
#define FLAG_ERROR 0x80

次に、個々のビットを読み書きします。

if (status & FLAG_BUSY) ... /* test if the device is busy */
status &= ~FLAG_ERROR; /* turn off error flag */
status |= FLAG_TRANSMISSION_IN_PROGRESS /* turn on transmission-in-progress flag */
于 2010-08-16T21:27:05.560 に答える