C++中具有按位数据的结构[duplicate]

rqdpfwrv  于 2022-12-01  发布在  其他
关注(0)|答案(4)|浏览(149)

此问题在此处已有答案

10年前就关门了。

可能重复:

Converting Bit Field to int
我正在开发一个应用程序,其中一部分处理包含多个1位标志的16位字。我使用类似于以下所示的结构来处理数据:

struct mystruct
{
   uint16_t Reserved1   :3;
   uint16_t WordErr     :1;
   uint16_t SyncErr     :1;
   uint16_t WordCntErr  :1;
   uint16_t Reserved2   :10;
};

即,该结构包含单个16位变量,该变量作为多个较小(在某些情况下,1位标志)片段来处理。
我的问题是,是否有一种简单的方法可以将整个16位字作为一个值来处理,比如说,将其输出到控制台、文件或添加到另一个数据结构中?除了移动各个结构元素并将它们添加到临时的uint16_t变量中之外,我不知道有什么方法可以做到这一点。似乎有一种更简单的方法可以提取整个字,但是我找不到任何有关编译器如何处理这样的结构的信息。
编辑:我想这可能是显而易见的,但我试图做的是能够单独访问1位标志,以及使用该结构作为一个单一的变量类型uint16_t(即无符号短,16位)。

jc3wubiy

jc3wubiy1#

这里的标准方法是使用匿名结构/联合,如下所示:

union mystruct
{
   struct
   {
      uint16_t Reserved1   :3;
      uint16_t WordErr     :1;
      uint16_t SyncErr     :1;
      uint16_t WordCntErr  :1;
      uint16_t Reserved2   :10;
   };

   uint16_t word_field;
};

或者,如果并集不适合作为顶层对象,

struct mystruct
{
   union
   {
       struct
       {
          uint16_t Reserved1   :3;
          uint16_t WordErr     :1;
          uint16_t SyncErr     :1;
          uint16_t WordCntErr  :1;
          uint16_t Reserved2   :10;
       };

       uint16_t word_field;
   };
};

此定义允许直接访问内部字段,如:

mystruct s1;
s1.WordCntErr = 1;

严格地说,编译器并不保证联合体的不同成员如何相互重叠。它可以使用不同的对齐,甚至移位。这里的很多人都会很容易地指出这一点。然而,从实际的Angular 来看,如果联合体的所有字段都有相同的大小,你可以安全地假设它们占用了同一块内存。例如,代码

s1.word_field = 0;

将所有位字段归零。大量的代码正在使用它。无法想象它会停止工作。

whhtz7ly

whhtz7ly2#

简短的回答是你做不到。长一点的回答是你能做到,但细节取决于你的编译器。这个特殊的位字段布局看起来很可疑,它应该Map到一个硬件寄存器,在这种情况下,你已经有了编译器依赖性:位域的排列细节是由实现定义的。因此,当你确信编译器按照你所期望的方式排列它们时,你也可以检查它是否支持通过联合体的类型双关语。尽管写入联合体的一个域并从另一个域读取会在形式上产生未定义的行为,但在C和C++中,大多数(所有?)编译器在像这样的简单情况下支持它。

jqjz2hbq

jqjz2hbq3#

作为来自联合技术的未定义行为的替代方法,您可以复制数据:

mystruct m;
m.Reserved1 = 0;
m.WordErr = 1;
m.SyncErr = 0;
m.WordCntErr = 0;
m.Reserved2 = 0;

uint16_t value = 0;
memcpy(&value, &m, sizeof(value));

Code(http://codepad.org/wa9ycDLX)
当然,输出是特定于平台的/对字节序敏感的,所以如果您计划将其写出以便可以再次读入,请考虑这一点。

2o7dmzc5

2o7dmzc54#

这就是union的用途。我几乎不需要使用它,所以我的语法可能有点生疏,但它看起来像这样:

union myunion
{
    struct mystruct
    {
       uint16_t Reserved1   :3;
       uint16_t WordErr     :1;
       uint16_t SyncErr     :1;
       uint16_t WordCntErr  :1;
       uint16_t Reserved2   :10;
    };
    uint16_t word;
};

当然,无论何时访问它,都会添加类型,所以如果只是偶尔需要,您可能只想尝试类型转换。

相关问题