0

I have a packet of data and when i assign that data to variables bit by bit as per the requirement, it is missing some bytes in between. Don't know why? I am working in c++.

For Example, I have structure like:

struct __attribute__((packed))
{
    uint32  varA:9;
    uint32  varB:10;
    uint32  varC:9;
    uint32  varD:4;
    uint16  varE:16;
    uint32  varF:32;
}structA;

And i have data as: a0 1a 0d 00 01 42 00 1c 17 2d

All thing goes well til variable varD. When come to varE, it should assign 01 42 to that but it is missing 01 and taking 42 only. And after that everything goes fine.

And if i do it like this

 struct __attribute__((packed))
{
    uint32  varA:9;
    uint32  varB:10;
    uint32  varC:9;
    uint32  varD:4;
    uint8   varE:8;
    uint8   varF:8;
    uint32  varG:32;
}structA;

The bits assigning works fine. Any idea why is this happening?

  • 2
    Please provide a [mre]. – Andreas Wenzel Aug 05 '20 at 08:29
  • 1
    structure members aren't guaranteed to be contiguous – Swift - Friday Pie Aug 05 '20 at 08:29
  • Does this answer your question? [How structure padding works?](https://stackoverflow.com/questions/9938679/how-structure-padding-works) – Swift - Friday Pie Aug 05 '20 at 08:30
  • @Swift-FridayPie No that is not the case. – Harsh Bansal Aug 05 '20 at 11:44
  • I added the example @AndreasWenzel – Harsh Bansal Aug 05 '20 at 11:52
  • @HarshBansal: What you have posted still is not an [mre], as it is not reproducible. For example, your code requires a function `main` in order to be reproducible. If you want to provide a reproducible example, you could for example define a byte sequence in memory like this: `char bytes[] = {0xE0, 0x3F, 0x43, 0x67, 0x72, 0xE4};` and then use [`std::memcpy`](https://en.cppreference.com/w/cpp/string/byte/memcpy) to copy those bytes into the struct and then print the individual struct members. Then you can post the actual output and expected output. – Andreas Wenzel Aug 05 '20 at 12:49
  • `__attribute__((packed))` is a compiler-specific extension which may not work on some compilers. Also, when used on gcc, [it has no effect on default settings with Microsoft Windows as the target platform](https://stackoverflow.com/q/63053490/12149471). Therefore, please specify your compiler and target platform. – Andreas Wenzel Aug 05 '20 at 13:04
  • 1
    What is `sizeof structA`? Does that expression evaluate to the same value with both structs posted in the question? – Andreas Wenzel Aug 05 '20 at 13:07
  • The complier i am using is MinGW 5.2 64-bit. And yes the both structure size is same. @AndreasWenzel – Harsh Bansal Aug 06 '20 at 04:48
  • 1
    The MinGW compiler is based on the gcc compiler. Are you targetting the Microsoft Windows platform? If yes, then this question is probably a duplicate of [this one](https://stackoverflow.com/q/63053490/12149471). – Andreas Wenzel Aug 06 '20 at 05:42
  • Yaa @AndreasWenzel. That is somehow answering my question. Thanks for your help. – Harsh Bansal Aug 06 '20 at 05:48
  • @HarshBansal `varE` can't share memory location with previous fields because it doesn't fit into the type length of memory location for them(`uint32_t`). Your case is even worse than a padding problem because order of bit fields is implementation-specific. And while standard says that memory locations of sequence non-zero length bit fields are contiguous, it doesn't mean that fields themselves are contiguous when crossing memory location border or ones that share same location are ordered same way (endianness usually flips the order). – Swift - Friday Pie Aug 06 '20 at 06:53
  • There are possible solutions that avoid all bit fields problems by use of classes with getter\setter methods or unions of structs with shared beginning sequence, each representing single field – Swift - Friday Pie Aug 06 '20 at 06:55

3 Answers3

1

The MinGW compiler is based on the GCC compiler.

On GCC, when targetting x86 platforms, the

__attribute__((__packed__))

only works on structs with

__attribute__((gcc_struct)).

However, when targetting Microsoft Windows platforms, the default attribute for structs is

__attribute__((ms_struct)).

Therefore, I see three ways to accomplish what you want:

  1. Use the compiler command-line option -mno-ms-bitfields to make all structs default to __attribute__((gcc_struct)).
  2. Explicitly use __attribute__((gcc_struct)) on your struct.
  3. Use #pragma pack instead of __attribute__((__packed__)).

Note: This answer is nearly identical to my answer to this similar question. Therefore, it may be appropriate to mark one of the questions as a duplicate. On the other hand, the situation in the question in this thread may be a bit different, because in the other question thread, bit-fields were not being used.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
0

The Issue you are seeing is most likely due to Padding. Within structures, Fields may might be spaced out between each other, in order to align to a 2, 4 or 8 byte offsets, eg:

struct Foo
{
    uint32_t a;  // 32 bits aligned to 4 byte offsets
    uint16_t b;  // 16 bits aligned to 4 byte offsets
    uint32_t c;  // 32 bits aligned to 4 byte offsets
};

In memory, if the CPU wants 4 byte boundaries, it may be layed out like so:

| Boundary 1        | Boundary 2        | Boundary 3
+----+----+----+----+----+----+----+----+----+----+----+----+----+
|  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 | 12 | Memory
|----+----+----+----+----+----+----+----+----+----+----+----+----|
|      Field A      | Field B | PADDING |        Field C         | Struct Layout
+----+----+----+----+----+----+----+----+----+----+----+----+----+
g-radam
  • 527
  • 1
  • 7
  • 20
  • I think the padding which i gave in my example structure is correct – Harsh Bansal Aug 05 '20 at 11:53
  • Why a uint32_t? have you tried casting it to something a little less specialist. A uint32_t has something to do with unassigned pointers or something. Whats up with just UINT32s instead. I note that the error appears on the variable at the 32 bit boundary. Ive never knowingly used an uint32_t before but what I see is some fancy struct of uint32/unint16 that should just fall into place wthout issue. Is it the _t thing maybe? – Stephen Duffy Aug 05 '20 at 12:02
  • 1
    @StephenDuffy i tried replacing uint32_t with simple unsigned int and uint16_t with the unsigned short. But the same problem persists. – Harsh Bansal Aug 05 '20 at 12:16
  • 1
    #pragma pack(2) will set packed structs to align on 2 byte boundaries. #pragma pack() will set it back to default - this is from gcc https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html doing something to provide ms compatability. I think that would just compile according to spec with gcc. Is it an ms compiler your using? Try the pragma directive to see if it fixes it. – Stephen Duffy Aug 05 '20 at 14:12
  • Apologies for any confusions, I wrote this prior to you editing your original post. I used the types "uint32_t" and "uint16_t" only to *explicitly* convey that I'm creating two 32-bit fields and a 16-bit field in the Foo struct above. This was to show you what the compiler will do by default when laying out Foo's fields memory. – g-radam Aug 06 '20 at 12:17
0

I got the solution as the @StephenDuffy said, i am missing pragma directive. After adding that, the code works fine for me.

the pragma directive is as:- #pragma pack(push,1)

and ending it as:- #pragma pack(pop)

  • Do the other two solutions that I mentioned in [my answer](https://stackoverflow.com/a/63075681/12149471) in the duplicate thread also work? As I have stated in my answer, `#pragma pack` is one of three possible solutions. – Andreas Wenzel Aug 06 '20 at 05:49
  • On the other hand, the behavior of the three solutions I specified in that answer may be different, because in the duplicate thread, the question was not using bit-fields. Therefore, it may be possible that only one of those solutions works. As far as I know, gcc and Microsoft use different rules for bit-fields. See the gcc documentation on the compiler command-line option [`-mno-ms-bitfields`](https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/x86-Options.html) for further information. – Andreas Wenzel Aug 06 '20 at 05:56
  • @AndreasWenzel i don't get chance to check for other two solutions as have to finish it and gave it for product release purpose. – Harsh Bansal Aug 15 '20 at 14:26