Structures with bitwise data in C++ [duplicate]

2020-05-21 05:54发布

Possible Duplicate:
Converting Bit Field to int

I am working on an application, part of which handles 16-bit words that contain a number of 1-bit flags. I am handling the data using a structure similar to the one shown below:

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

i.e. the structure contains a single 16-bit variable that is handled as a number of smaller (in some cases, 1-bit flag) pieces.

My question is this, is there a simple way to handle the entire 16-bit word as one value, say, to output it to the console, or a file, or add it to another data structure? I don't know of any way of doing this besides shifting the individual structure elements and adding them to a temporary uint16_t variable. It seems that there is probably a simpler way of extracting the entire word, but I can't find any information on how the compiler handles a structure like this.

EDIT: I suppose this may be obvious but what I am trying to do in a nutshell is be able to access the 1-bit flags individually, as well as use the structure as a single variable of type uint16_t (i.e. unsigned short, 16 bits).

4条回答
别忘想泡老子
2楼-- · 2020-05-21 06:07

That's what a union is for. I hardly ever need to use one, so my syntax may be rusty, but it looks something like this:

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

Of course, that adds typing whenever you access it, so you might want to just try a typecast if you only need it occasionally.

查看更多
来,给爷笑一个
3楼-- · 2020-05-21 06:11

An alternative to the undefined behavior that comes from the union technique, you could copy the data:

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]

Of course, the output is platform-specific / endian-sensitive, so if you plan on writing it out so you can read it in again then take that into account.

查看更多
干净又极端
4楼-- · 2020-05-21 06:22

The standard approach here is to use anonymous structs/unions, like this:

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

or, if union is not good as a top level object,

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

This definition allows direct access to the inner fields, like:

mystruct s1;
s1.WordCntErr = 1;

Strictly speaking, compiler is not giving any guarantees on how different members of the union will overlap each other. It can use different alignments and even shifts. A lot of people here will readily point this out. Nevertheless, looking at this from the practical standpoint, if all fields of the union have the same size you can safely assume that they occupy the same piece of memory. For example, the code

s1.word_field = 0;

will zero out all bit fields. Tons of code are using this. It is unthinkable this will ever stop working.

查看更多
啃猪蹄的小仙女
5楼-- · 2020-05-21 06:22

The short answer is you can't do it. The longer answer is that you can do it, but the details depend on your compiler. This particular bit-field layout looks suspiciously like it's supposed to map to a hardware register, in which case you've already got compiler dependencies: the details of how the bit-fields are arranged is implementation-defined. So while you're assuring yourself that the compiler lays them out the way you expect, you can also check whether it supports type puns through a union. Although writing to one field of a union and reading from another formally produces undefined behavior, both in C and in C++, most (all?) compilers support it in simple cases like this.

查看更多
登录 后发表回答