首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Bit操作良好实践

Bit操作良好实践
EN

Stack Overflow用户
提问于 2018-11-02 12:45:08
回答 7查看 3.5K关注 0票数 34

作为一个初学者C程序员,我想知道,什么是最好的易于阅读和易于理解的解决方案设置控制位在一个设备。有什么标准吗?有可模仿的示例代码吗?谷歌没有给出任何可靠的答案。

例如,我有一个控制块映射:

我看到的第一种方法就是简单地设置所需的位。它需要一堆解释,在评论,似乎没有那么专业。

代码语言:javascript
复制
DMA_base_ptr[DMA_CONTROL_OFFS] = 0b10001100;

我看到的第二种方法是创建一个位字段。我不确定是否应该坚持这样做,因为我从来没有遇到过这样的使用方式(与我提到的第一个选项不同)。

代码语言:javascript
复制
struct DMA_control_block_struct
{ 
    unsigned int BYTE:1; 
    unsigned int HW:1; 
    // etc
} DMA_control_block_struct;

其中一种比另一种好吗?有什么我看不见的选择吗?

如有任何建议,将不胜感激。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2018-11-02 12:53:19

位字段的问题是,C标准并没有规定定义它们的顺序与实现它们的顺序相同。所以你可能不是在设定你认为你在做的事情。

C标准第6.7.2.1p11节规定:

实现可以分配任何足以容纳位字段的可寻址存储单元。如果有足够的空间,在结构中立即跟随另一个位场的位场应被包装成同一单元的相邻位元。如果空间不足,是否将不适合的位字段放入下一个单元或重叠相邻单元是实现定义的。在单元内分配位字段的顺序(从高阶到低阶或低阶到高阶)是实现定义的。可寻址存储单元的对齐方式未指定。

例如,查看struct iphdr的定义,它表示一个IP报头,它来自Linux上的/usr/include/netinet/ip.h文件:

代码语言:javascript
复制
struct iphdr
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ihl:4;
    unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
    unsigned int version:4;
    unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
    u_int8_t tos;
    ...

您可以在这里看到,根据实现的不同,位字段以不同的顺序放置。您也不应该使用这个特定的检查,因为这个行为是系统依赖的。这个文件是可以接受的,因为它是系统的一部分。其他系统可能以不同的方式实现这一点。

所以不要用位字段。

最好的方法是设置所需的位。但是,为每个位定义命名常量并对要设置的常量执行按位或位的操作是有意义的。例如:

代码语言:javascript
复制
const uint8_t BIT_BYTE =     0x1;
const uint8_t BIT_HW   =     0x2;
const uint8_t BIT_WORD =     0x4;
const uint8_t BIT_GO   =     0x8;
const uint8_t BIT_I_EN =     0x10;
const uint8_t BIT_REEN =     0x20;
const uint8_t BIT_WEEN =     0x40;
const uint8_t BIT_LEEN =     0x80;

DMA_base_ptr[DMA_CONTROL_OFFS] = BIT_LEEN | BIT_GO | BIT_WORD;
票数 40
EN

Stack Overflow用户

发布于 2018-11-02 13:31:42

其他答案已经涵盖了大部分内容,但可能值得一提的是,即使您不能使用非标准的0b语法,也可以使用移位将1位按位号移动到位置,即:

代码语言:javascript
复制
#define DMA_BYTE  (1U << 0)
#define DMA_HW    (1U << 1)
#define DMA_WORD  (1U << 2)
#define DMA_GO    (1U << 3)
// …

注意最后一个数字是如何与文档中的“位号”列匹配的。

设置和清除位的用法没有改变:

代码语言:javascript
复制
#define DMA_CONTROL_REG DMA_base_ptr[DMA_CONTROL_OFFS]

DMA_CONTROL_REG |= DMA_HW | DMA_WORD;    // set HW and WORD
DMA_CONTROL_REG &= ~(DMA_BYTE | DMA_GO); // clear BYTE and GO
票数 19
EN

Stack Overflow用户

发布于 2018-11-02 12:54:32

传统的C方法是定义一组位元:

代码语言:javascript
复制
#define WORD  0x04
#define GO    0x08
#define I_EN  0x10
#define LEEN  0x80

然后你的初始化就变成

代码语言:javascript
复制
DMA_base_ptr[DMA_CONTROL_OFFS] = WORD | GO | LEEN;

您可以使用|设置各个位

代码语言:javascript
复制
DMA_base_ptr[DMA_CONTROL_OFFS] |= I_EN;

可以使用&~清除单个位。

代码语言:javascript
复制
DMA_base_ptr[DMA_CONTROL_OFFS] &= ~GO;

您可以使用&测试单个位。

代码语言:javascript
复制
if(DMA_base_ptr[DMA_CONTROL_OFFS] & WORD) ...

不过,绝对不要使用位字段。它们有它们的用途,但当外部规范定义位元在某些地方时,它们就有其用途了,就像我假设的那样。

另见20.72.26C常见问题单中的问题。

票数 18
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53118858

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档