Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

c - Bitfields and alignment

Trying to pack data into a packet. This packet should be 64 bits. I have this:

typedef union {
  uint64_t raw;
  struct {
    unsigned int magic    : 8;
    unsigned int parity   : 1;
    unsigned int stype    : 8;
    unsigned int sid      : 8;
    unsigned int mlength  : 31;
    unsigned int message  : 8;
  } spacket;
} packet_t;

But it seems that alignment is not guaranteed. Because when I run this:

#include <strings.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

const char *number_to_binary(uint64_t x)
{
    static char b[65];
    b[64] = '';

    uint64_t z;
    int w = 0;
    for (z = 1; w < 64; z <<= 1, ++w)
    {
        b[w] = ((x & z) == z) ? '1' : '0';
    }

    return b;
}

int main(void)
{
  packet_t ipacket;
  bzero(&ipacket, sizeof(packet_t));
  ipacket.spacket.magic = 255;
  printf("%s
", number_to_binary(ipacket.raw));
  ipacket.spacket.parity = 1;
  printf("%s
", number_to_binary(ipacket.raw));
  ipacket.spacket.stype = 255;
  printf("%s
", number_to_binary(ipacket.raw));
  ipacket.spacket.sid = 255;
  printf("%s
", number_to_binary(ipacket.raw));
  ipacket.spacket.mlength = 2147483647;
  printf("%s
", number_to_binary(ipacket.raw));
  ipacket.spacket.message = 255;
  printf("%s
", number_to_binary(ipacket.raw));
}

I get (big endian):

1111111100000000000000000000000000000000000000000000000000000000
1111111110000000000000000000000000000000000000000000000000000000
1111111111111111100000000000000000000000000000000000000000000000
1111111111111111111111111000000000000000000000000000000000000000
1111111111111111111111111000000011111111111111111111111111111110
1111111111111111111111111000000011111111111111111111111111111110

My .mlength field is lost somewhere on the right part although it should be right next to the .sid field.

This page confirms it: Alignment of the allocation unit that holds a bit field is unspecified. But if this is the case, how do people are packing data into bit fields which is their purpose in the first place?

24 bits seems to be the maximum size the .mlength field is able to take before the .message field is kicked out.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Almost everything about the layout of bit-fields is implementation-defined in the standard, as you'd find from numerous other questions on the subject on SO. (Amongst others, you could look at Questions about bitfields and especially Bit field's memory management in C).

If you want your bit fields to be packed into 64 bits, you'll have to trust that your compiler allows you to use 64-bit types for the fields, and then use:

typedef union {
  uint64_t raw;
  struct {
    uint64_t magic    : 8;
    uint64_t parity   : 1;
    uint64_t stype    : 8;
    uint64_t sid      : 8;
    uint64_t mlength  : 31;
    uint64_t message  : 8;
  } spacket;
} packet_t;

As originally written, under one plausible (common) scheme, your bit fields would be split into new 32-bit words when there isn't space enough left in the current one. That is, magic, parity, stype and sid would occupy 25 bits; there isn't enough room left in a 32-bit unsigned int to hold another 31 bits, so mlength is stored in the next unsigned int, and there isn't enough space left over in that unit to store message so that is stored in the third unsigned int unit. That would give you a structure occupying 3 * sizeof(unsigned int) or 12 bytes — and the union would occupy 16 bytes because of the alignment requirements on uint64_t.

Note that the standard does not guarantee that what I show will work. However, under many compilers, it probably will work. (Specifically, it works with GCC 5.3.0 on Mac OS X 10.11.4.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...