1

Let's say I have a struct and variables in C like this:

typedef struct {
  uint8_t x;
  uint8_t y;
  uint8_t z;
}my_type;

my_type a;
my_type a10[10];

With C99 is it certain that

  • sizeof(a) == 3? (and not 4 or 8)
  • sizeof(a10) == 30? (and not 40 or 80)
  • 1
    No there may be padding so it may and probably will be larger. – Fredrik Jul 17 '20 at 16:02
  • 1
    According to the C standard, padding could be added anywhere after the first member (which is at the same address as the whole structure). While there is no particular reason why an implementation would need to add padding in this case, it is free to do so. – Ian Abbott Jul 17 '20 at 16:03
  • 3
    @Fredrik: It will not probably be larger. No normal C implementation adds padding to this structure except by special request of the user or some special purpose. The C standard **permits** an implementation to add padding, but normal C implementations do not—the probability that a randomly chosen C implementation will give this structure a larger size is zero or near zero. – Eric Postpischil Jul 17 '20 at 16:19
  • @EricPostpischil Every "normal" compiler for ARM will absolutely pad this to four bytes, and most x86 compilers will as well, unless you specifically ask for it to be packed. 32-bit alignment is the norm, not the exception. – Lee Daniel Crocker Jul 17 '20 at 16:26
  • @LeeDanielCrocker: [No, not every normal compiler for ARM will absolutely pad this to four bytes.](https://godbolt.org/z/zrGWrs) – Eric Postpischil Jul 17 '20 at 16:35
  • My experience matches @EricPostpischil – bruceg Jul 17 '20 at 16:55
  • @Lee Daniel Crocker, Re "*and most x86 compilers will as well*", `gcc` doesn't. `clang` doesn't. Which compilers did you have in mind? – ikegami Jul 17 '20 at 17:01
  • You guys seem to be right--at the end of the structure it doesn't pad. Maybe I'm remembering earlier versions. Notice, though, that if you add an int as the fourth member, the size becomes 8, so it pads when there's stuff after it. – Lee Daniel Crocker Jul 17 '20 at 17:09
  • @LeeDanielCrocker The structure itself may need to be aligned to 32 or 64 bits, but that doesn't mean it must be padded to fill a full 32-bit/64-bit block. What you might be remembering is when a struct contains members with different alignment requirements. For example, change `b` to `uint16_t`, and you'll see padding happen after `a` and after `c` on most compilers. – MemReflect Jul 17 '20 at 17:37
  • @Lee Daniel Crocker, It would pad if you had `struct { double d; uint8_t b; }` so you could do `malloc(sizeof(...) * n)` and end up with `n` properly-aligned structs. But no padding is needed to achieve that with the OP's struct because there's no alignment restrictions on a struct consisting entirely of chars. Explained in more details on this [here](https://stackoverflow.com/q/62253943/589924). – ikegami Jul 17 '20 at 19:18
  • @MemReflect, Re "*The structure itself may need to be aligned to 32 or 64 bits, but that doesn't mean it must be padded to fill a full 32-bit/64-bit block.*", Actually, it does, so you can have an array of the struct. – ikegami Jul 17 '20 at 19:25
  • Gábor Kiss-Vámosi, Curious, should the answer be yes or no, what difference does this make for your code? Why care? – chux - Reinstate Monica Jul 17 '20 at 22:22
  • @ikegami [GCC](https://godbolt.org/z/fYd37n) [Clang](https://godbolt.org/z/9n915d) [ICC](https://godbolt.org/z/4xnYzf) and [MSVC](https://godbolt.org/z/rqTzcn) all indicate there is no padding between elements of an array of the struct in the question for x86-64. That's not to say all implementations behave the same or that the same implementation may yield identical results on a different CPU architecture. Multiple compilers confirm that padding is not always added, meaning there is no rule stating padding must or must not be added. – MemReflect Jul 18 '20 at 04:36
  • @MemReflect, The struct in your tests doesn't require 32/64-bit alignment, so all your tests are irrelevant. Your comment is pointless, and mine stands: Padding is required to fill a full 32/64-bit block for structs that need to be aligned to 32/64 bits. You wouldn't be able to do `structs[1]` otherwise. Feel free to test this by replacing `uint8_t a` with `double a`. Padding will be added to the end so that the struct is 0x10 bytes in size instead of 0x0A in all four the compilers you mentioned. – ikegami Jul 18 '20 at 08:18
  • @chux-ReinstateMonica This type will be used as color for an RGB888 framebuffer. So it's important to NOT have space between the adjacent RGB values. – Gábor Kiss-Vámosi Jul 18 '20 at 17:39
  • I've tested with GCC on x64 and there is no padding. – Gábor Kiss-Vámosi Jul 18 '20 at 17:40
  • Just tried on STM32F429 (ARM Cortex M4) with GCC using with O0, Os and O3 and there was no padding either. – Gábor Kiss-Vámosi Jul 18 '20 at 17:58
  • @ikegami I was confused about something else, I guess, because thinking about things now, what you say makes sense. Thank you for taking the time to correct my misguided notions. – MemReflect Jul 18 '20 at 20:58

2 Answers2

1

With C99 is it certain that sizeof(a) == 3?

This type will be used as color for an RGB888 framebuffer. So it's important to NOT have space between the adjacent RGB values.

typedef struct {
  uint8_t x;
  uint8_t y;
  uint8_t z;
}my_type;

No. The size may be 3 or 4 (or theoretically others, but not likely)


2 solutions:

  • Give up portability and use compiler specif code to pack the structure.

  • Change struct to an array of 3 uint8_t and adjust code.

I recommend the last.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

As mentioned in the comments, padding could be added by default.
To avoid that you could use __attribute__((packed)) for your struct.
This will tell the compiler to pack your struct as tight as possible.
Would look like this:

typedef struct {
  uint8_t x;
  uint8_t y;
  uint8_t z;
} __attribute__((packed)) my_type;
Lessi
  • 165
  • 7
  • 5
    Important missing information: This is a gcc extension, this has no effect in this case because gcc will already produce a packed struct, and it could affect performance if it did have an effect. – ikegami Jul 17 '20 at 17:05