Switching bits in C ++

I have the following structure:

struct SysData { // Topic (32 bits) UTL_UINT16_Tdef SystemID:11; // set to decimal 25 UTL_UINT16_Tdef TypeID:5; // set to 2 (telemetry type) UTL_UINT16_Tdef ContentID; // set to decimal 1234 } SysData MsgHdr; MsgHdr.SystemID = 25; MsgHdr.TypeID = 2; MsgHdr.ContentID = 0; 

If I do something like this:

  unsigned int a; memcpy(&a, &MsgHdr, sizeof(MsgHdr)); headerInfo[0] = a & 0x7FF; headerInfo[1] = (a >> 16) & 31; headerInfo[2] = (a >> 21) & 0xFFFF; 

headerInfo [0] should be 25, but it has 36. What am I doing wrong?

+4
source share
5 answers

You should not be aware of the internal representation of SysData.Compiler can choose to combine bit fields together or not to align them left or right, etc. It can even display them up to 32-bit integers for performance. You just can't know. The unused portion of the bitfield may contain garbage, and probably where you got 36.

This is strange, but not very difficult to verify. Change your 25 to other values ​​and see what you get.

However, memcopying your structure for some unsigned int is probably not a good idea. Why don't you access the bitfield directly? As in headerInfo[0] = MsgHdr.SystemID; for which beats. In your example, memcopy is just a waste of time (and also dangerous, as you can see).

+3
source

The implementation of bitfields is undefined and depends on which compiler you use.

(EDIT: ignore my incorrect guess about where 36 is from)

I can't think of how you get to 36, but with bitfields I would highly recommend reading them using the normal read access functions, instead of moving them, i.e.

 SysData *pSysData = (SysData *) &MsgHdr; headerInfo[0] = pSysData->ContentID; 

By the way, I do not understand your example. You say that headerInfo [0] should be 25. But it should not be 0? In your example, it says ContentID is 0, and I realized what you are reading there.

0
source

With the exception of possible problems with the end user or packaging problems, should you not change the shift in headerInfo [1] to 11, and headerInfo [2] to 16?

0
source

Like EboMike, it’s impossible to determine where you get 36

a) decimal value 25 = 00000011001 b) decimal value 2 = 00010 c) decimal 1234 = 000010011010010

Thus, various combinations:

  • abc = 0000001 [100100] 010000010011010010
  • acb = 0000001 [100100] 00100110 [100100] 0010
  • bac = 000100000001 [100100] 0010011010010
  • bca = 0001000001001101001000000011001
  • cab = 0000100110 [100100] 000001 [100100] 010
  • cba = 0000100110 [100100] 001000000011001

Nothing ends in the required sequence of 100100 bits, so if the structure is not actually stored over two uint or something awkward happens, I get lost. Download to the debugger and see what is actually stored.

0
source

If I do this:

 #include <stdio.h> #include <memory.h> typedef unsigned short UTL_UINT16_Tdef; struct SysData { // Topic (32 bits) UTL_UINT16_Tdef SystemID:11; // set to decimal 25 UTL_UINT16_Tdef TypeID:5; // set to 2 (telemetry type) UTL_UINT16_Tdef ContentID; // set to decimal 1234 }; int main() { SysData MsgHdr; MsgHdr.SystemID = 33; MsgHdr.TypeID = 22; MsgHdr.ContentID = 11; unsigned int a; memcpy(&a, &MsgHdr, sizeof(MsgHdr)); /* headerInfo[0] = a & 0x7FF; headerInfo[1] = (a >> 16) & 31; headerInfo[2] = (a >> 21) & 0xFFFF; */ printf( "%08X %i\n", a, sizeof(SysData) ); printf( "0: %i\n", a & 0x7FF ); printf( "1: %i\n", (a >> 11) & 31 ); printf( "2: %i\n", (a >> 16) & 0xFFFF ); } 

I get the expected results, and the code also does - http://codepad.org/XNm0Yp90

0
source

All Articles