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

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

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

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

当然,但你真的想用一个结构来定义这样的位

 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

你有几种可能性。 一种是使用布尔数学来获取位:

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

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

正如已经说过的那样,你不能解决小于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) } 

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

 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; 

在C中可寻址的最小单元始终是一个字节(在C中称为char )。 你不能直接访问。 获取访问位的最接近方法是定义一个名为bitpointer的数据类型,并bitpointer定义一些函数或宏:

 #include  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)。

您可以通过将这些位放在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 */