简体   繁体   中英

Bit shifting in C++

I have the following struct:

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 have the value 25, but it has 36. What am I doing wrong?

You shouldn't guess on the internal representation of SysData.Compiler may choose to pack bit fields together or not, to align them left or right, etc. It can even choose to map them to 32 bits integer for performances issue. You just can't know. The unused part of the bitfield may contain garbage and it's probably where you got your 36.

It's strange, but not really hard to check. Change your 25 to other values and see what you get.

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

The implementation of bitfields is not defined and varies based on what compiler you use.

(EDIT: Ignore my incorrect guess on where the 36 is coming from)

I can't think of how you would get to 36, but with bitfields, I would strongly recommend reading them using plain read access functions instead of shifting them around, ie

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

Btw, I don't understand your example. You're saying headerInfo[0] should be 25. But shouldn't it be 0? Your example says ContentID is 0, and I figured that's what you're trying to read there.

除了可能的endian问题或打包问题之外,headerInfo [1]的转换不应该是11而headerInfo [2]应该是16吗?

Like EboMike, can't figure where you're getting 36

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

So the different combinations are:

  • 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 there ends in the required 100100 bit sequence, so unless the struct is actually being stored over two uints or something wacky is going on, I'm lost. Load up into a debugger and see what a actually stores.

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 expected results, and codepad does too - http://codepad.org/XNm0Yp90

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM