4

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?

6
  • What is the type of headerInfo? Commented Aug 7, 2010 at 0:41
  • @mjschultz headerInfo is an unsigned int array Commented Aug 7, 2010 at 0:42
  • Why are you doing it that way ... would a union not be suitable? Commented Aug 7, 2010 at 0:48
  • 1
    I see the proper value in MSVC, FWIW Commented Aug 7, 2010 at 0:59
  • 1
    Also, the expressions for headerInfo[1] and headerInfo[2] aren't what I'd expect them to be: (a >> 11) & 31 and (a >> 16) & 0xffff Commented Aug 7, 2010 at 1:08

5 Answers 5

3

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).

Sign up to request clarification or add additional context in comments.

Comments

0

Other than possible endian issues or packing issues, shouldn't the shift on headerInfo[1] be 11 and headerInfo[2] be 16?

Comments

0

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, i.e.

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.

5 Comments

"Should be zero" assuming appropriate endianess.
No, "should be zero" meaning that he explicitly said ContentID=0 in the example, and given that the second piece of code ANDs the result with 0x7ff, it looks like he's going for ContentID.
Why define an intermediate pointer to SysData ? Just read MsgHdr.SystemID or MsgHdr.ContentID as needed.
Depends on what type MsgHdr is - My guess was that the second code block read a data stream, and MsgHdr was a pointer to raw data or something. I have no explanation why else he would go through the complicated way of extracting the information via bit-shifts rather than just reading the members directly.
Your guess may be right or it could be some newbie error. I don't understand either why he is doing things that way. The question probably need some more details (and fully working code sample instead of fragments would also be cool).
0

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.

Comments

0

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

3 Comments

with which compiler and which compilation options ?
Depends on the compiler. The bitfield implementation is not defined, so trying to extract data from them directly is playing Russian Roulette.
gcc/msc/intelc on x86, but the point was to check whether my version doesn't work right for OP, or it does, and he did something wrong elsewhere. We don't have the full source here, or even type definitions.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.