ZeZNiQ
ZeZNiQ

Reputation: 708

Difference between packing a struct vs union vs enum

What is the difference between packing a struct vs. union vs. enum?

Regarding packed struct vs. packed union, there seems to be a minor difference in the assembly code generated on armv7l (but not on x86_64):

#include <stdio.h>

struct uint18_struct {
        unsigned int var:18;
} __attribute__((packed));

typedef struct uint18_struct uint18_struct_t;

union uint18_union {
        unsigned int var:18;
} __attribute__((packed));

typedef union uint18_union uint18_union_t;

int main (void)
{
        unsigned int bar = ~0U;
        volatile uint18_struct_t foo = *((uint18_struct_t *) &bar);
        printf ("max of uint18_t = %u\n", foo.var);
        volatile uint18_union_t baz = *((uint18_union_t *) &bar);
        printf ("max of bf_u18_t = %u\n", baz.var);
        return 0;
}

Generated assembly for foo and baz:

        volatile uint18_struct_t foo = *((uint18_struct_t *) &bar);
   10358:   f107 020c   add.w   r2, r7, #12
   1035c:   f107 0308   add.w   r3, r7, #8
   10360:   8811        ldrh    r1, [r2, #0]
   10362:   7892        ldrb    r2, [r2, #2]
   10364:   8019        strh    r1, [r3, #0]
   10366:   709a        strb    r2, [r3, #2]

        volatile uint18_union_t baz = *((uint18_union_t *) &bar);
   1037a:   f107 020c   add.w   r2, r7, #12
   1037e:   1d3b        adds    r3, r7, #4
   10380:   8811        ldrh    r1, [r2, #0]
   10382:   7892        ldrb    r2, [r2, #2]
   10384:   8019        strh    r1, [r3, #0]
   10386:   709a        strb    r2, [r3, #2]

Notice how the first two lines in the generated assembly (above ldrh) differs.

System details:

$ uname -a
Linux beaglebone 4.19.19-bone-rt-r21 #1stretch Wed Feb 6 11:01:34 UTC 2019 armv7l GNU/Linux
$ gcc --version
gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Cmdline I used:

$ gcc -g -O0 --save-temps main.c

Which one would you prefer to represent a uint18_t type - packed struct or packed union? Why?


EDIT: Imagine an embedded controller needing to process raw data of 9-bits (but CHAR_BIT is still 8) each (hence, the need for uint18_t) and does not provide stdint.h, limits.h.

Upvotes: 1

Views: 136

Answers (1)

chux
chux

Reputation: 153456

Which one would you prefer to represent a uint18_t type (?)

As

struct uint18_struct {
  uint_least32_t var:18;
}

without the __attribute__((packed)). It is most portable that way.

On a 16-bit int system, hope that it accepts 32-bit int types in bit fields.

Otherwise consider the following and handle the sub-range needs myself.

struct uint18_struct {
  uint_least32_t var;
}

IMO, OP has not made a good case yet for needing the packing. Perhaps once the larger issue is stated, we can work to solve the real problem.

Upvotes: 0

Related Questions