Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: Are designated initializer supposed to zero padding? Date: Tue, 12 May 2026 09:36:41 -0700 Organization: A noiseless patient Spider Lines: 155 Message-ID: <86bjekmvom.fsf@linuxsc.com> References: <10tqqso$kn23$1@dont-email.me> <86jytar6n2.fsf@linuxsc.com> <10trvca$topc$1@dont-email.me> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Date: Tue, 12 May 2026 16:36:44 +0000 (UTC) Injection-Info: dont-email.me; logging-data="2216482"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/+zeuNzeZ0MODtIPshPzoMYegp2HOGkIw="; posting-host="714746643ff61f997ea29d517f63563d" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:hIWNBi+Ww42bdJw69MhuA80kLeo= sha1:52AJUWRsufOHMKVTfPURDe6JB4Q= sha256:YJQbDEUOMytrVbsgiH7jdHPMQ+dPlDCg7ey02V0aZlY= sha1:6ZGpIPyMVrAMCy8wKHlbqZ1sees= Xref: csiph.com comp.lang.c:398819 highcrew writes: > Hello, > > On 5/11/26 5:01 AM, Tim Rentsch wrote: > >> highcrew writes: >> >> You seem to be asking two different questions, one about padding >> and one about flexible array members. The example code is >> incomplete, so it's hard to be sure exactly what your questions >> are, but let me take a stab at being helpful. > > Yes, perhaps I was a little confusing. > The fact the "actual" array is a struct with FAM is orthogonal. > The interesting bit is that the whole memory chunk is zeroed > via calloc. > > ...yet it was lucky that I mentioned it, so you could show > me that neat initialization of local variable variable with FAM. > >> Point 1: initializers are not required to set padding (either >> padding bits or padding bytes). Don't expect padding to be >> zeroed. This statement applies to initializers in all forms - >> regular initializers, designated initializers, and compound >> literals. > > OK, this is the confirmation that I was after. > > The problem has roots in the fact I've noticed that some compilers will > just translate the initialization into a memset-zero or equivalent. > But I could not find any requirement from the standard. > > tl;dr: > This is of course not implying that the standard says so. memset-zero > is just a reasonable way to initialize all fields. > > Thanks for confirming it. I'm sorry for my earlier bad answer. It turns out that the rule changed between C99 and C11. In C99, a static struct with no initializer had its padding bits set to unspecified values. In C11 and later, the same situation DOES set padding bits to zero. There are some subtleties when initializing a struct when one of its members has an initializer, and I won't try to describe those here. If you are interested, please read my responses to Keith Thompson's posts. (Again my thanks to Keith for pointing out a key passage that I missed.) >> Point 3: if you want to initialize and zero a struct, along with >> elements of a non-trivial flexible array member, probably the best >> way to do that is as part of a union with an array of unsigned char, >> for example as follows: >> [...] >> >> struct array *stuff = >> &(union { >> unsigned char uca[ SUITABLE_SIZE ]; >> struct array fam; >> }){ .uca = { 0 } }.fam; >> >> assuming I haven't made any mistakes in transcription. >> >> Admittedly this is ugly but maybe it can be used to accomplish >> what you want. > > I find that quite clean, as I said above. > > Thoughts: > > - I tried to experiment with using a struct instead of a union, > by having the `struct array` first and an array of items afterwards, > but the compiler doesn't allow that. I suppose because that would > be a direct declaration of FAM struct, even if in my intention the > following array of items is meant as a tail to it... > So I understand the union is needed. Fair enough.[1] Yeah, it's important to use a union. > - If I got your idea correctly, the `uca` array is initialized > by the `.uca = {0}` part and that is going to zero out the > whole padding too, since it is an array of bytes. Exactly right. After posting it occurred to me it would be good to wrap this pattern in a macro. Here is a full example: //// start here //// /* macros to help with declaring structs with flexible array members at file scope or in expressional contexts. */ typedef struct { unsigned n; // size of array char s[]; // the flexible array member } ExampleFAMstruct; /* the macros */ #define FAM_STRUCT_POINTER( T, id, fa_member, n, ucaname, structname ) \ T *id = &FAM_STRUCT( T, fa_member, n, ucaname, structname ) #define FAM_STRUCT( T, fa_member, n, ucaname, structname ) ( \ (union { \ unsigned char ucaname[ FAM_STRUCT_SIZE( T, fa_member, n ) ]; \ T structname; \ }){ .ucaname = { 0 } }.structname \ ) #define FAM_STRUCT_SIZE( T, fa_member, n ) ( \ sizeof (T) + (n) * sizeof ((T*)0)->fa_member[0] \ ) /* an example use */ FAM_STRUCT_POINTER( ExampleFAMstruct, file_scope_p, s, 100, uca, the_struct ); #include int main(){ /* a second example use */ FAM_STRUCT_POINTER( ExampleFAMstruct, p, s, 20, uca, the_struct ); printf( " the pointer is %p\n", (void*)p ); printf( "the file scope pointer is %p\n", (void*)file_scope_p ); } //// end here //// If anyone is curious, the reason for the ucaname and structname macro parameters it to avoid accidental collisions (even if they might be unlikely) with names used elsewhere. It should be easy to change the macro definitions to take them out if they aren't wanted. > Thanks for sharing! > > > [1] side note: I always find unions a bit ...shaky... since that day > I discovered how different they are in C++. Now I don't use > C++ these days, but it still feels uncomfortably wonky to use > unions. I have been traumatized! :P Here is my rule of thumb for unions: In C, unions work. In C++, they don't. Probably that isn't exactly right, but it's a good first approximation.