mschrimpf
mschrimpf

Reputation: 559

Enforce struct size 8 byte

I have a struct that is supposed to be 8 byte in size.

struct Slot {
    uint8_t T;
    uint8_t S;
    uint32_t O : 24;
    uint32_t L : 24;
}

However, sizeof(Slot) tells me the size is 12 byte. So the compiler seems to pad the data although it shouldn't be necessary (probably because the 24-bit cannot be aligned properly).

A hacky solution would be to use 3 one-byte fields instead of a single three-byte field:

struct Slot2 {
    uint8_t T;
    uint8_t S;
    uint8_t O1;
    uint8_t O2;
    uint8_t O3;
    uint8_t L1;
    uint8_t L2;
    uint8_t L3;
}; // sizeof(Slot2) = 8

Is there any other way to achieve this?

Upvotes: 2

Views: 1638

Answers (7)

Mike Vine
Mike Vine

Reputation: 9837

On MSVC the following works and keeps your variable orders the same:

struct Slot {
    uint64_t T : 8;
    uint64_t S : 8;
    uint64_t O : 24;
    uint64_t L : 24;
};

This is not guaranteed across compilers though. YMMV on other compilers.

Upvotes: 0

simon
simon

Reputation: 1240

With this compiler dependant solution (works with gcc, msvc) the struct will be 8 bytes:

#pragma pack(push, 1)
struct Slot {
    uint8_t T;
    uint8_t S;
    uint32_t O : 24;
    uint32_t L : 24;
};
#pragma pack(pop)

This will set the alignment of the struct to 1 byte.

Upvotes: 0

Lundin
Lundin

Reputation: 213892

There is no way anyone can tell what your code will do or how the data will end up in memory, because the behavior of bit fields is poorly specified by the C standard. See this.

  • It is not specified what will happen when you use an uint32_t for a bit field.
  • You can't know if there will be padding bits.
  • You can't know if there will be padding bytes.
  • You can't know where padding bits or bytes will end up.
  • You can't know whether 8 bits of the 2nd 24 bit chunk end up immediately after previous data, or if it is aligned to the next 32 bit segment.
  • You can't know which bit that is msb and which that is lsb.
  • Endianess will cause problems.

The solution is to not use bit fields at all. Use the bitwise operators instead.

Upvotes: 3

gnasher729
gnasher729

Reputation: 52538

Your "hack" solution is exactly the right one. I suspect that the layout is determined by some outside factors, so you won't be able to map this to a struct in any better way. I suspect the order of bytes in your 24 bit numbers is also determined by the outside, and not by your compiler.

To handle that kind of situation, a struct of bytes or just an array of bytes is the easiest and portable solution.

Upvotes: 2

Weather Vane
Weather Vane

Reputation: 34585

This gives size 8 bytes on MSVC without packing pragma.

struct Slot {
    uint32_t O : 24;
    uint32_t T : 8;
    uint32_t L : 24;
    uint32_t S : 8;
};

Upvotes: 3

Sourav Ghosh
Sourav Ghosh

Reputation: 134336

I think, what you want, 8 bytes, is not something that the C standard can gurantee, with your first definition.

Related: from C11 standard, Chapter §6.7.2.1,

An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined.

You can have a way out however, if you can adjust the variable so that they can fit properly in 32-bit alignment, then

24 + 8 + 24 + 8 = 64 bits = 8 bytes.

you can have a structure of size 8 bytes.

Upvotes: 0

Nipun Talukdar
Nipun Talukdar

Reputation: 5387

Try something like as shown below:

struct Slot {
    uint32_t O : 24;
    uint8_t T;
    uint32_t L : 24;
    uint8_t S;
};

Upvotes: -3

Related Questions