Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何以可读的方式使用C初始化寄存器中的位_C_Bit Manipulation - Fatal编程技术网

如何以可读的方式使用C初始化寄存器中的位

如何以可读的方式使用C初始化寄存器中的位,c,bit-manipulation,C,Bit Manipulation,我有一个24位寄存器,它包含许多字段。例如,上面的3位是“模式”,下面的10位是“数据速率除数”,等等。现在,我可以计算出这24位中的内容,并将其编码为单个十六进制数0xnnnn。然而,对于任何试图维护它的人来说,这是相当难以理解的 问题是,如果我单独定义每个子字段,那么将其全部编码在一起的最佳方式是什么?经典方式是使用解决方案1 解决此问题的“标准”方法是对成员使用struct。大概是这样的: typedef struct { int divisor: 10; unsigned

我有一个24位寄存器,它包含许多字段。例如,上面的3位是“模式”,下面的10位是“数据速率除数”,等等。现在,我可以计算出这24位中的内容,并将其编码为单个十六进制数0xnnnn。然而,对于任何试图维护它的人来说,这是相当难以理解的


问题是,如果我单独定义每个子字段,那么将其全部编码在一起的最佳方式是什么?

经典方式是使用
解决方案1
解决此问题的“标准”方法是对成员使用
struct
。大概是这样的:

typedef struct {
    int divisor: 10;
    unsigned int field1: 9;
    char field2: 2;
    unsigned char mode: 3;
} fields;
每个字段名后面的数字指定该成员使用的位数。在上面的示例中,
除数
字段使用10位,可以存储
-512
511
(带符号整数)之间的值,而
模式
可以存储3位上的无符号值:介于
0
7
之间

每个字段的值范围使用有关有符号/无符号和的常规规则,但字段长度(char/int/long)限于指定的位数。当然,
char
最多可以保存8位,而
short
最多可以保存16位。强制规则是字段类型的常用规则,考虑到字段的大小(即,在
模式下存储
-5
会将其转换为
无符号
(实际值可能是
3

您需要注意几个问题(其中一些问题也在文档页面的注释部分提到,关于:

  • 结构中声明的位总量必须为24(寄存器的大小)
  • 由于您的结构使用3个字节,因此此类结构数组中的某些位置可能会表现出奇怪的行为,因为它们跨越分配单元大小(通常为4或8个字节,具体取决于硬件)
  • 该标准不保证分配单元中位字段的顺序;根据体系结构的不同,可能在最终的3字节包中,字段
    模式
    包含最高有效位3位或最低有效位3位;不过,您可以很容易地解决这一问题
您可能需要一次性处理存储在
字段
结构中的值。为此,您可以将该结构嵌入到联合中:

typedef union {
   fields f;
   unsigned int a;
} reg;

reg x;
/* Access individual fields */
x.f.mode = 2;
x.f.divisor = 42;
/* Get the entire register */
printf("%06X\n", x.a);
解决方案2 做同样事情的另一种方法是使用宏来提取字段并组成整个寄存器:

#define MAKE_REG(mode, field2, field1, divisor) \
         ((((mode) & 0x07) << 21) | \
         (((field2) & 0x03) << 19) | \
         (((field1) & 0x01FF) << 10 )| \
         ((divisor) & 0x03FF))

#define GET_MODE(reg) (((reg) & 0xE00000) >> 21)
#define GET_FIELD2(reg) (((reg) & 0x180000) >> 19)
#define GET_FIELD1(reg) (((reg) & 0x07FC00) >> 10)
#define GET_DIVISOR(reg) ((reg) & 0x0003FF)
#定义MAKE_REG(模式、字段2、字段1、除数)\
((模式)和0x07)>19)
#定义GET_字段1(reg)((reg)和0x07FC00)>>10)
#定义GET_除数(reg)((reg)&0x0003FF)
第一个宏将
模式
字段2
字段1
除数
值组合成一个3字节的整数。另一组宏提取各个字段的值。所有这些宏都假定处理后的数字是无符号的

利弊
struct
(嵌入
union
)解决方案:

  • [+]
    它允许编译器对要输入字段的值进行一些检查(并发出警告);此外,它还可以在有符号和无符号之间进行正确的转换
宏观解决方案:

  • [+]
    内存对齐问题是不明智的,您将位放在您想要的位置
  • (-)
    它不会检查您在字段中输入的值的范围
  • (-)
    使用宏处理有符号值有点棘手;此处建议的宏仅适用于无符号值;使用有符号值需要更多移位

您可以使用模式3除数1的{3,0,0,1}将其初始化为若干整数
#define MAKE_REG(mode, field2, field1, divisor) \
         ((((mode) & 0x07) << 21) | \
         (((field2) & 0x03) << 19) | \
         (((field1) & 0x01FF) << 10 )| \
         ((divisor) & 0x03FF))

#define GET_MODE(reg) (((reg) & 0xE00000) >> 21)
#define GET_FIELD2(reg) (((reg) & 0x180000) >> 19)
#define GET_FIELD1(reg) (((reg) & 0x07FC00) >> 10)
#define GET_DIVISOR(reg) ((reg) & 0x0003FF)