3

Consider this code. Existence of padding is guaranteed.

static_assert(_Alignof(char) < _Alignof(double), "Flip!");
static_assert(sizeof(char) < sizeof(double), "Flop!");

struct S {
    char c[1];
    double d;
};
union U {
    char c[1];
    double d;
};

static_assert(sizeof(struct S) == _Alignof(double) * sizeof(double), "Fudge!");
static_assert(sizeof(union U) == sizeof(double), "Futz!");

S s; U u;
s.c[1] = 0; // What?
u.c[1] = 0; // What?

With those static_asserts, it's sure there's padding in the middle or at the end. Is it safe to access them?

iBug
  • 35,554
  • 7
  • 89
  • 134
  • 5
    Afaik this is UB since compiler is allowed to do bound checking for arrays in debug build whenever possible. As for type punnig there is a question on that: [Is type-punning through a union unspecified in C99, and has it become specified in C11? Ask](https://stackoverflow.com/questions/11639947/is-type-punning-through-a-union-unspecified-in-c99-and-has-it-become-specified) –  Dec 24 '17 at 13:30
  • 1
    alligbnment has not to much to overloading array, usually not detected, because of neighbour field, but `c[1]` is an error – Jacek Cz Dec 24 '17 at 15:26
  • 3
    You can't access the padding reliably. You can't rely on the padding being copied under structure (union) assignment. It's "safe" to access them in the sense that there are bytes there. There's nothing meaningful or reliable you can do with them. If you have a use for such bytes, be explicit: `struct S2 { char c[1]; short s; int i; double d; }` (on most systems except 32-bit Intel x86, that'll be the same size as `struct S` in the question). And I believe your first static assert would fire on 32-bit x86. – Jonathan Leffler Dec 24 '17 at 16:34
  • @JonathanLeffler By 32-bit x86 you mean something older than a Pentium 4 or any modern CPU with a 32-bit OS? What would happen instead? – iBug Dec 24 '17 at 16:36
  • 1
    I compiled (tried to compile the amended form of) your code on a Mac (x86_64 chip), and using a 32-bit compile forced with `gcc -m32` I get: `x86-89.c:15:1: error: static assertion failed: "Fudge!"` — `static_assert(sizeof(struct S) == 2 * sizeof(double), "Fudge!");` — because the `double` only has to be 4-byte aligned there. (So, I'm not digging deep into arcane platforms; just compiling for 32-bit on a modern Intel CPU.) – Jonathan Leffler Dec 24 '17 at 16:44
  • 3
    Accessing `c[1]` in either `s` or `u` is UB, regardless of any alignment or padding. – n. m. could be an AI Dec 24 '17 at 17:15
  • 2
    Why don't you just declare some variables that occupy the "padding" bytes? Then you won't have to ask whether it's OK to access them. – David K Dec 24 '17 at 18:38
  • How about `*(s.c + 1) = ...` – n.caillou Dec 24 '17 at 19:26
  • Technically you can do this. Practically - why you need it? In short - use it in special cases, mostly as "hack" and not for normal / commercial software. – i486 Dec 24 '17 at 22:56
  • @JonathanLeffler Now the new static assertion passes 32-bit x86. – iBug Dec 25 '17 at 03:24

1 Answers1

0

It is safe to memcpy(), memset() or similar an entire structure, even if it contains padding bits. However, no assumptions can be made about the padding retaining its value.

Therefore, the only use in accessing padding bits is that it is not necessary to write code to avoid accessing it in some situations.

For operations like memcmp() it is still wrong to access padding bits since the result would be unpredictable.

jilles
  • 10,509
  • 2
  • 26
  • 39