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

发布于 2024-09-14 18:28:33 字数 208 浏览 9 评论 0原文

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

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

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

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

静谧 2024-09-21 18:28:33

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

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。

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.bit1 if you ommit the u from the typedef.

昇り龍 2024-09-21 18:28:33

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

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

第一种(至少可以说)更便携,但是当您处理状态位时,很可能代码甚至不是无论如何,稍微便携一点,所以你可能不太关心这一点......

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

农村范ル 2024-09-21 18:28:33
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;
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;
云裳 2024-09-21 18:28:33

正如已经说过的,你不能在 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)
}

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

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

#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 ().

指尖微凉心微凉 2024-09-21 18:28:33

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

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

#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-defined whether they are filled msb-to-lsb or lsb-to-msb (see ISO C99, 6.7.2.1p10).

那伤。 2024-09-21 18:28:33

您可以通过将这些位放入联合内的结构中来完成此操作,但它可能会也可能不会起作用,具体取决于您的实现。语言定义没有指定单独的位以什么顺序与unsigned char的位匹配;更糟糕的是,它甚至不能保证这些位将与 unsigned char 重叠(编译器可能决定将单独的位放置在单词的最重要一侧,而 unsigned char< /code> 朝向最不重要的一侧,反之亦然)。

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

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

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 char towards the least significant side or vice versa).

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 */
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文