C语言 有没有办法通过联合访问单个位?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3497345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:12:02  来源:igfitidea点击:

Is there a way to access individual bits with a union?

cstructurebitsunions

提问by PICyourBrain

I am writing a C program. I want a variable that I can access as a char but I can also access the specific bits of. I was thinking I could use a union like this...

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

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

but the compiler doesn't like this. Apparently you can't use bits in a structure. So what can I do instead?

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

回答by torak

Sure, but you actually want to use a struct to define the bits like this

当然,但您实际上想使用结构来定义这样的位

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;

Then you can access for DeviceStatus ds;you can access ds.u.bit1. Also, some compilers will actually allow you to have anonymous structures within a union, such that you can just access ds.bit1if you ommit the u from the typedef.

然后你可以访问为DeviceStatus ds;你可以访问ds.u.bit1。此外,一些编译器实际上允许您在联合中拥有匿名结构,这样您就可以在ds.bit1省略 typedef 中的 u 时进行访问。

回答by Jerry Coffin

You have a couple of possibilities. One would be to just use Boolean math to get at the bits:

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

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

Another is to use bitfields:

另一种是使用位域:

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

The first is (at least arguably) more portable, but when you're dealing with status bits, chances are that the code isn't even slightly portable anyway, so you may not care much about that...

第一个是(至少可以说)更便携,但是当您处理状态位时,代码可能无论如何都没有稍微便携,所以您可能不太关心......

回答by Kevin Vermeer

As has already been stated, you can't address memory smaller than a byte in C. I would write a macro:

正如已经说过的,你不能在 C 中寻址小于一个字节的内存。我会写一个宏:

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

and use it to access the bits. That way, your access is the same, regardless of the size of the structure you're accessing. You would write your code as:

并使用它来访问位。这样,无论您访问的结构的大小如何,您的访问都是相同的。您可以将代码编写为:

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

This gets you access close to your proposed system, which would use [] instead of ().

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

回答by Jon Hanna

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;

回答by Roland Illig

The smallest unit that is addressable in C is always a byte (called charin C). You cannot access a bit directly. The closest way to get to accessing bits would be to define a data type called bitpointerand define some functions or macros for it:

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

I recommend against unions because it is implementation-definedwhether they are filled msb-to-lsb or lsb-to-msb (see ISO C99, 6.7.2.1p10).

我建议不要使用联合,因为它是实现定义的,无论它们是填充 msb-to-lsb 还是 lsb-to-msb(参见 ISO C99,6.7.2.1p10)。

回答by Gilles 'SO- stop being evil'

You can do it by putting the bits in a struct inside the union, but it may or may not work, depending on your implementation. The language definition does not specify in what order the separate bits will be matched with the bits of the unsigned char; worse, it doesn't even guarantee that the bits will overlap with the unsigned char(the compiler might decide to place the separate bits towards the most significant side of a word and the unsigned chartowards the least significant side or vice versa).

您可以通过将位放在联合内部的结构中来实现,但它可能会或可能不会起作用,具体取决于您的实现。语言定义没有指定单独的位将与 ; 的位匹配的顺序unsigned char。更糟糕的是,它甚至不能保证这些位会与unsigned char(编译器可能决定将单独的位放在一个字的最重要的一侧和最不重要的一侧,unsigned char反之亦然)。

The usual technique in your situation is to use bitwise operations. Define constants named after the meaning of the bits, e.g.,

在您的情况下,常用的技术是使用按位运算。定义以位的含义命名的常量,例如,

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

Then to read and write individual bits:

然后读取和写入单个位:

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 */