有没有办法通过联合访问各个位?

时间:2010-08-16 21:05:13

标签: c structure bits unions

我正在写一个C程序。我想要一个我可以作为char访问的变量,但我也可以访问特定的位。我以为我可以使用像这样的工会......

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

但是编译器不喜欢这个。显然你不能在结构中使用位。 那么我该怎么做呢?

6 个答案:

答案 0 :(得分:21)

当然,但你实际上想用一个结构来定义像这样的位

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。此外,一些编译器实际上允许您在联合中使用匿名结构,这样如果您从typedef中省略u,则只能访问ds.bit1

答案 1 :(得分:4)

你有几种可能性。一种方法是使用布尔数学来得到位:

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...

另一种方法是使用位域:

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...

第一个(至少可以说是)可移植性更强,但是当你处理状态位时,很可能代码甚至不是轻微可移植的,所以你可能并不在乎......

答案 2 :(得分:3)

正如已经说过的那样,你不能解决小于C字节的内存。我会写一个宏:

#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)
}

这使您可以访问您建议的系统,该系统将使用[]而不是()。

答案 3 :(得分:1)

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;

答案 4 :(得分:0)

C中可寻址的最小单位始终是一个字节(在C中称为char)。你不能直接访问一下。获取访问位的最接近方法是定义一个名为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)。

答案 5 :(得分:0)

您可以通过将这些位放在union中的结构中来实现,但它可能会也可能不会起作用,具体取决于您的实现。语言定义没有指定单独的位将以什么顺序与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 */