Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #398672 > unrolled thread

Are designated initializer supposed to zero padding?

Started byhighcrew <high.crew3868@fastmail.com>
First post2026-05-10 22:47 +0200
Last post2026-05-12 01:00 +0300
Articles 20 on this page of 31 — 8 participants

Back to article view | Back to comp.lang.c


Contents

  Are designated initializer supposed to zero padding? highcrew <high.crew3868@fastmail.com> - 2026-05-10 22:47 +0200
    Re: Are designated initializer supposed to zero padding? James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-10 19:15 -0400
      Re: Are designated initializer supposed to zero padding? highcrew <high.crew3868@fastmail.com> - 2026-05-11 09:11 +0200
        Re: Are designated initializer supposed to zero padding? James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-05-12 16:02 -0400
          Re: Are designated initializer supposed to zero padding? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-12 21:10 -0700
            Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-13 15:51 -0700
              Re: Are designated initializer supposed to zero padding? David Brown <david.brown@hesbynett.no> - 2026-05-14 11:36 +0200
                Re: Are designated initializer supposed to zero padding? Richard Harnden <richard.nospam@gmail.invalid> - 2026-05-14 11:47 +0100
                  Re: Are designated initializer supposed to zero padding? David Brown <david.brown@hesbynett.no> - 2026-05-14 14:11 +0200
                Re: Are designated initializer supposed to zero padding? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-14 15:55 -0700
                  Re: Are designated initializer supposed to zero padding? David Brown <david.brown@hesbynett.no> - 2026-05-15 10:20 +0200
    Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-10 20:01 -0700
      Re: Are designated initializer supposed to zero padding? highcrew <high.crew3868@fastmail.com> - 2026-05-11 09:10 +0200
        Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-12 09:36 -0700
      Re: Are designated initializer supposed to zero padding? scott@slp53.sl.home (Scott Lurndal) - 2026-05-11 15:34 +0000
        Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-11 18:23 -0700
      Re: Are designated initializer supposed to zero padding? Michael S <already5chosen@yahoo.com> - 2026-05-11 23:22 +0300
        Re: Are designated initializer supposed to zero padding? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-11 14:34 -0700
          Re: Are designated initializer supposed to zero padding? Michael S <already5chosen@yahoo.com> - 2026-05-12 00:55 +0300
            Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-11 15:27 -0700
            Re: Are designated initializer supposed to zero padding? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-11 16:07 -0700
        Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-11 15:19 -0700
          Re: Are designated initializer supposed to zero padding? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-11 16:10 -0700
            Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-11 18:13 -0700
              Re: Are designated initializer supposed to zero padding? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-11 18:28 -0700
                Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-11 21:59 -0700
                  Re: Are designated initializer supposed to zero padding? David Brown <david.brown@hesbynett.no> - 2026-05-12 09:15 +0200
                  Re: Are designated initializer supposed to zero padding? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-05-12 00:27 -0700
                    Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-12 06:44 -0700
        Re: Are designated initializer supposed to zero padding? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-05-11 18:15 -0700
    Re: Are designated initializer supposed to zero padding? Michael S <already5chosen@yahoo.com> - 2026-05-12 01:00 +0300

Page 1 of 2  [1] 2  Next page →


#398672 — Are designated initializer supposed to zero padding?

Fromhighcrew <high.crew3868@fastmail.com>
Date2026-05-10 22:47 +0200
SubjectAre designated initializer supposed to zero padding?
Message-ID<10tqqso$kn23$1@dont-email.me>
Hello,

I recently wrote a unit test, where I'm verifying that some array
of data matches the expected value. The comparison is done by looping
on individual items, and invoking a comparison function for each of
them.

   struct item { long a, b; in c; };
   struct array { unsigned int n; struct item a[] }; // FAM

   const struct item expected[] = {
     {1, 2, 3},
     {4, 5, 6},
   };

   struct array *actual = get(); // using calloc under the hood
   assert(compare_array(expected, ARRSIZE(expected), actual) == 0);
   free(actual);

Oh, and I cheated on the comparison, thinking I could get away with a
memcmp():

   int compare(const struct item *a, const struct item *b)
   {
      return memcmp(a, b, sizeof *a);
   }

This test worked as intended under Debian (gcc 14.2.0), and failed under
Alpine Linux (gcc 15.2.0. But it works with clang).

Why? Because the padding of course.  It is OK in the `actual`
array thanks to the fact I'm using `calloc()` under the hood, but it is
not zero-initialized in `expected`, declared on the stack.
The clean solution: don't cheat nor assume padding is zeroed out, and
write a proper comparison function.

...

But then I started to wonder: isn't a designated initializer
supposed to wipe the memory? I definitely seen that happen, but
this is of course not saying it *must* happen.

I can't find anything in the standard (I checked N3220). I
only found a mention of static and thread local objects, but
nothing about objects declared on the stack.

So, is the compiler only required to clear individual fields?
Can it leave dirty memory on padding?  Or did I hit a compiler
bug?

-- 
High Crew

[toc] | [next] | [standalone]


#398678

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2026-05-10 19:15 -0400
Message-ID<10tr3ia$nak8$1@dont-email.me>
In reply to#398672
On 2026-05-10 16:47, highcrew wrote:
> Hello,
> 
> I recently wrote a unit test, where I'm verifying that some array
> of data matches the expected value. The comparison is done by looping
> on individual items, and invoking a comparison function for each of
> them.
> 
>    struct item { long a, b; in c; };
>    struct array { unsigned int n; struct item a[] }; // FAM
> 
>    const struct item expected[] = {
>      {1, 2, 3},
>      {4, 5, 6},
>    };
> 
>    struct array *actual = get(); // using calloc under the hood
>    assert(compare_array(expected, ARRSIZE(expected), actual) == 0);
>    free(actual);
> 
> Oh, and I cheated on the comparison, thinking I could get away with a
> memcmp():
> 
>    int compare(const struct item *a, const struct item *b)
>    {
>       return memcmp(a, b, sizeof *a);
>    }
> 
> This test worked as intended under Debian (gcc 14.2.0), and failed under
> Alpine Linux (gcc 15.2.0. But it works with clang).
> 
> Why? Because the padding of course.  It is OK in the `actual`
> array thanks to the fact I'm using `calloc()` under the hood, but it is
> not zero-initialized in `expected`, declared on the stack.
> The clean solution: don't cheat nor assume padding is zeroed out, and
> write a proper comparison function.
> 
> ...
> 
> But then I started to wonder: isn't a designated initializer
> supposed to wipe the memory?

When you provide an initializer list,

"... all subobjects that are not initialized explicitly are subject to
default initialization." (6.7.21p23).

When an object is default-initialized,

"— if it is an aggregate, every member is initialized (recursively)
according to these rules, and any padding is initialized to zero bits;
— if it is a union, the first member that is not an unnamed bit-field is
initialized (recursively) according to these rules, and any padding is
initialized to zero bits." (6.7.21p15).

While you do provide an initializer list, so those clauses should be
applicable, you make no use of designated initializers in the code that
you've shown. Why are you asking about them?

There at two kinds of designated initializers. This provides an example
of each, in the context of your code:

const struct item designated[2] = {
     [1]={ 1, 2, 3},
     {.b=1}
}

The above is equivalent to:
const struct item designated[2] = {
     { 0, 1, 0},
     { 1, 2, 3}
}

[toc] | [prev] | [next] | [standalone]


#398711

Fromhighcrew <high.crew3868@fastmail.com>
Date2026-05-11 09:11 +0200
Message-ID<10trver$topc$2@dont-email.me>
In reply to#398678
On 5/11/26 1:15 AM, James Kuyper wrote:
> When you provide an initializer list,
> 
> "... all subobjects that are not initialized explicitly are subject to
> default initialization." (6.7.21p23).
> 
> When an object is default-initialized,
> 
> "— if it is an aggregate, every member is initialized (recursively)
> according to these rules, and any padding is initialized to zero bits;
> — if it is a union, the first member that is not an unnamed bit-field is
> initialized (recursively) according to these rules, and any padding is
> initialized to zero bits." (6.7.21p15).

I've seen this section in the standard, and I thought I found what
I was seeking for, but isn't it just referring to static and
thread-local variables?

-- 
High Crew

[toc] | [prev] | [next] | [standalone]


#398826

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2026-05-12 16:02 -0400
Message-ID<10u010b$12a0c$1@dont-email.me>
In reply to#398711
On 2026-05-11 03:11, highcrew wrote:
> On 5/11/26 1:15 AM, James Kuyper wrote:
>> When you provide an initializer list,
>>
>> "... all subobjects that are not initialized explicitly are subject to
>> default initialization." (6.7.21p23).

That citation has a typo, it should have been 6.7.11p23.

>> When an object is default-initialized,
>>
>> "— if it is an aggregate, every member is initialized (recursively)
>> according to these rules, and any padding is initialized to zero bits;
>> — if it is a union, the first member that is not an unnamed bit-field is
>> initialized (recursively) according to these rules, and any padding is
>> initialized to zero bits." (6.7.21p15).

And that one should have been 6.7.11p14

> I've seen this section in the standard, and I thought I found what
> I was seeking for, but isn't it just referring to static and
> thread-local variables?

No, earlier in the same section it says quite explicitly: "... If an
object that has static or thread storage duration is not initialized
explicitly, or any object is initialized with an empty initializer,
...". Objects with automatic storage duration are still covered by the
second clause of that sentence.

[toc] | [prev] | [next] | [standalone]


#398842

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-05-12 21:10 -0700
Message-ID<10u0tiv$2egqj$1@kst.eternal-september.org>
In reply to#398826
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
> On 2026-05-11 03:11, highcrew wrote:
[...]
>> I've seen this section in the standard, and I thought I found what
>> I was seeking for, but isn't it just referring to static and
>> thread-local variables?
>
> No, earlier in the same section it says quite explicitly: "... If an
> object that has static or thread storage duration is not initialized
> explicitly, or any object is initialized with an empty initializer,
> ...". Objects with automatic storage duration are still covered by the
> second clause of that sentence.

Yes, but only automatic storage duration objects with an empty
initializer.  An "empty initializer" is `{}`, which wasn't even
legal pre-C23.  `{0}` is often used to (try to) achieve the same
effect; it specifies a value of 0 for the (recursively) first scalar
subobject, and leaves everything else to be default-initialized.

I have a feeling that there's something inconsistent about the
C23 rules.  I'm working on nailing down the specifics.

As a programmer, perhaps the best approach is to arrange things so
you don't have to care about what's stored in padding.  That might
mean that you can't use memcmp() to confirm that a struct has the
right value; you have to compare member by member.

[...]

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#398912

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-05-13 15:51 -0700
Message-ID<865x4qkjnu.fsf@linuxsc.com>
In reply to#398842
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

> James Kuyper <jameskuyper@alumni.caltech.edu> writes:
>
>> On 2026-05-11 03:11, highcrew wrote:
>
> [...]
>
>>> I've seen this section in the standard, and I thought I found what
>>> I was seeking for, but isn't it just referring to static and
>>> thread-local variables?
>>
>> No, earlier in the same section it says quite explicitly: "... If an
>> object that has static or thread storage duration is not initialized
>> explicitly, or any object is initialized with an empty initializer,
>> ...".  Objects with automatic storage duration are still covered by the
>> second clause of that sentence.
>
> Yes, but only automatic storage duration objects with an empty
> initializer.  An "empty initializer" is `{}`, which wasn't even
> legal pre-C23.  `{0}` is often used to (try to) achieve the same
> effect;  it specifies a value of 0 for the (recursively) first scalar
> subobject, and leaves everything else to be default-initialized.
>
> I have a feeling that there's something inconsistent about the
> C23 rules.  I'm working on nailing down the specifics.
>
> As a programmer, perhaps the best approach is to arrange things so
> you don't have to care about what's stored in padding.  That might
> mean that you can't use memcmp() to confirm that a struct has the
> right value;  you have to compare member by member.

My preference would be for a compiler option (eg -fzero-padding) or
a pragma (eg #pragma ZERO_PADDING=ON) or perhaps both.  Either of
those has advantages over changing the language definition, not the
least of which is they can be retrofitted to earlier versions of C
without needing to break conformance.

[toc] | [prev] | [next] | [standalone]


#398934

FromDavid Brown <david.brown@hesbynett.no>
Date2026-05-14 11:36 +0200
Message-ID<10u452a$28j9$1@dont-email.me>
In reply to#398912
On 14/05/2026 00:51, Tim Rentsch wrote:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
> 
>> James Kuyper <jameskuyper@alumni.caltech.edu> writes:
>>
>>> On 2026-05-11 03:11, highcrew wrote:
>>
>> [...]
>>
>>>> I've seen this section in the standard, and I thought I found what
>>>> I was seeking for, but isn't it just referring to static and
>>>> thread-local variables?
>>>
>>> No, earlier in the same section it says quite explicitly: "... If an
>>> object that has static or thread storage duration is not initialized
>>> explicitly, or any object is initialized with an empty initializer,
>>> ...".  Objects with automatic storage duration are still covered by the
>>> second clause of that sentence.
>>
>> Yes, but only automatic storage duration objects with an empty
>> initializer.  An "empty initializer" is `{}`, which wasn't even
>> legal pre-C23.  `{0}` is often used to (try to) achieve the same
>> effect;  it specifies a value of 0 for the (recursively) first scalar
>> subobject, and leaves everything else to be default-initialized.
>>
>> I have a feeling that there's something inconsistent about the
>> C23 rules.  I'm working on nailing down the specifics.
>>
>> As a programmer, perhaps the best approach is to arrange things so
>> you don't have to care about what's stored in padding.  That might
>> mean that you can't use memcmp() to confirm that a struct has the
>> right value;  you have to compare member by member.
> 
> My preference would be for a compiler option (eg -fzero-padding) or
> a pragma (eg #pragma ZERO_PADDING=ON) or perhaps both.  Either of
> those has advantages over changing the language definition, not the
> least of which is they can be retrofitted to earlier versions of C
> without needing to break conformance.

I'd prefer any changes or improvements to be in the standards, and also 
for compilers to have flags supporting the feature in previous C 
standards.  There's no reason not to have both - especially when AFAICS 
providing more situations where padding is zeroed cannot harm correct 
code (though it could conceivably affect efficiency).

I have a feeling that I read somewhere about a proposed standard library 
function that could be used to zero all padding bits and bytes in a 
struct.  Unfortunately, I can't remember where I saw it - and there is a 
fair chance it was a C++ proposal rather than a C proposal.

Anyway, for Tim's benefit (assuming he reads my posts), gcc 15 has a 
"-fzero-init-padding-bits" flag.  From the list of changes for gcc 15:

"""
{0} initializer in C or C++ for unions no longer guarantees clearing of 
the whole union (except for static storage duration initialization), it 
just initializes the first union member to zero. If initialization of 
the whole union including padding bits is desirable, use {} (valid in 
C23 or C++) or use -fzero-init-padding-bits=unions option to restore the 
old GCC behavior.
"""


And from the manual:


"""
-fzero-init-padding-bits=value

     Guarantee zero initialization of padding bits in automatic variable 
initializers. Certain languages guarantee zero initialization of padding 
bits in certain cases, e.g. C23 when using empty initializers ({}), or 
C++ when using zero-initialization or C guarantees that fields not 
specified in an initializer have their padding bits zero initialized. 
This option allows to change when padding bits in initializers are 
guaranteed to be zero initialized. The default is 
-fzero-init-padding-bits=standard, which makes no further guarantees 
than the corresponding standard. E.g.

       struct A { char a; unsigned long long b; char c; };
       union B { char a; unsigned long long b; };
       struct A a = {}; // C23 guarantees padding bits are zero.
       struct A b = { 1, 2, 3 }; // No guarantees.
       union B c = {}; // C23 guarantees padding bits are zero.
       union B d = { 1 }; // No guarantees.

     -fzero-init-padding-bits=unions guarantees zero initialization of 
padding bits in unions on top of what the standards guarantee, if the 
initializer of an union is empty (then all bits of the union are zero 
initialized) or if the initialized member of the union is smaller than 
the size of the union (in that case guarantees padding bits outside of 
the initialized member to be zero initialized). This was the GCC 
behavior before GCC 15 and in the above example guarantees zero 
initialization of last sizeof (unsigned long long) - 1 bytes in the union.

     -fzero-init-padding-bits=all guarantees additionally zero 
initialization of padding bits of other aggregates, so the padding in 
between b.a and b.b (if any) and tail padding in the structure (if any).
"""


[toc] | [prev] | [next] | [standalone]


#398939

FromRichard Harnden <richard.nospam@gmail.invalid>
Date2026-05-14 11:47 +0100
Message-ID<10u498q$791g$1@dont-email.me>
In reply to#398934
On 14/05/2026 10:36, David Brown wrote:
> """
> {0} initializer in C or C++ for unions no longer guarantees clearing of 
> the whole union (except for static storage duration initialization), it 
> just initializes the first union member to zero. If initialization of 
> the whole union including padding bits is desirable, use {} (valid in 
> C23 or C++) or use -fzero-init-padding-bits=unions option to restore the 
> old GCC behavior.
> """

"except for static storage duration initialization"

Does that guarentee that this will always be zeroed, even for padding, 
and even if NULL is not all-bits-zero ... ?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct foo
{
     int a;
     unsigned long b;
     char c;
     void *d;
     double e;
};

static struct foo FOO_INIT;

int main(void)
{
     struct foo *foo = malloc(sizeof *foo);
     unsigned char *x = (unsigned char *) foo;

     memcpy(foo, &FOO_INIT, sizeof *foo);

     printf("foo->a = %d\n", foo->a);
     printf("foo->b = %lu\n", foo->b);
     printf("foo->c = '%c'\n", foo->c);
     printf("foo->d = %p\n", foo->d);
     printf("foo->e = %f\n", foo->e);

     for (size_t i=0; i<sizeof *foo; i++)
         printf("%2.2x", x[i]);
     printf("\n");

     return 0;
}

I'd assume that there will be padding between foo.c and foo.d at the 
minimum.  Anyway, I get:

foo->a = 0
foo->b = 0
foo->c = ''
foo->d = (nil)
foo->e = 0.000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000

[toc] | [prev] | [next] | [standalone]


#398943

FromDavid Brown <david.brown@hesbynett.no>
Date2026-05-14 14:11 +0200
Message-ID<10u4e63$bv6n$1@dont-email.me>
In reply to#398939
On 14/05/2026 12:47, Richard Harnden wrote:
> On 14/05/2026 10:36, David Brown wrote:
>> """
>> {0} initializer in C or C++ for unions no longer guarantees clearing 
>> of the whole union (except for static storage duration 
>> initialization), it just initializes the first union member to zero. 
>> If initialization of the whole union including padding bits is 
>> desirable, use {} (valid in C23 or C++) or use -fzero-init-padding- 
>> bits=unions option to restore the old GCC behavior.
>> """
> 
> "except for static storage duration initialization"
> 

I read it that the "except" part means static duration padding zeroing 
is not affected by the change - static duration objects have their 
padding zeroed as before.  Others here are more reliable sources of 
standards requirements than I am, but I know enough about how the 
initialisation of static duration objects works in gcc to talk about 
that.  Static duration data (file-scope objects and local static 
objects) are either explicitly initialised, or default initialised to zero.

In the first case, objects are allocated in ".data" sections and prior 
to main(), their initialisation data is copied verbatim from a read-only 
part of the binary.  This read-only copy is generated by the compiler 
and covers all the bytes of the object - including padding.  So it is 
natural that the padding bytes here are zero.  In the second case, the 
objects are allocated in the ".bss" sections and are zeroed by, 
effectively, a memset() operation.  (On some platforms the OS will 
provide the memory ready-cleared, but the effect is the same.)  gcc does 
not support any targets for which bytes of zero are unsuitable for 
floating point or pointer zeroing.

So for anything of static duration, zero padding initialisation is 
guaranteed.  (This is specifically for gcc, but I believe it applies to 
all real-world compilers.  I have seen some compilers with more 
sophisticated pre-main initialisation, but all gave the same result.)

> Does that guarentee that this will always be zeroed, even for padding, 
> and even if NULL is not all-bits-zero ... ?
> 
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> 
> struct foo
> {
>      int a;
>      unsigned long b;
>      char c;
>      void *d;
>      double e;
> };
> 
> static struct foo FOO_INIT;
> 
> int main(void)
> {
>      struct foo *foo = malloc(sizeof *foo);
>      unsigned char *x = (unsigned char *) foo;
> 
>      memcpy(foo, &FOO_INIT, sizeof *foo);
> 
>      printf("foo->a = %d\n", foo->a);
>      printf("foo->b = %lu\n", foo->b);
>      printf("foo->c = '%c'\n", foo->c);
>      printf("foo->d = %p\n", foo->d);
>      printf("foo->e = %f\n", foo->e);
> 
>      for (size_t i=0; i<sizeof *foo; i++)
>          printf("%2.2x", x[i]);
>      printf("\n");
> 
>      return 0;
> }
> 
> I'd assume that there will be padding between foo.c and foo.d at the 
> minimum.  Anyway, I get:
> 
> foo->a = 0
> foo->b = 0
> foo->c = ''
> foo->d = (nil)
> foo->e = 0.000000
> 00000000000000000000000000000000000000000000000000000000000000000000000000000000
> 
> 

To my knowledge, you will always get this behaviour in real-world 
compilers.  That includes gcc 15 onwards - the change there is purely 
for local variables.


[toc] | [prev] | [next] | [standalone]


#398971

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-05-14 15:55 -0700
Message-ID<10u5jt4$uo0d$1@kst.eternal-september.org>
In reply to#398934
David Brown <david.brown@hesbynett.no> writes:
[...]
> I have a feeling that I read somewhere about a proposed standard
> library function that could be used to zero all padding bits and bytes
> in a struct.  Unfortunately, I can't remember where I saw it - and
> there is a fair chance it was a C++ proposal rather than a C proposal.

You're probably thinking of memset_explicit(), standardized in C23.

N3220 7.26.6.2:

    The memset_explicit function copies the value of c (converted to an
    unsigned char) into each of the first n characters of the object
    pointed to by s. The purpose of this function is to make sensitive
    information stored in the object inaccessible.

Footnote:

    The intention is that the memory store is always performed
    (i.e. never elided), regardless of optimizations. This is in
    contrast to calls to the memset function (7.26.6.1)

The only difference in the standard between the descriptions
of memset() and memset_explicit() is the second sentence and
the footnote.  I'm not convinced that that's enough to formally
specify that an implementation that optimizes away a call to
memset_explicit() is non-conforming.  But I think implementations
will follow the intent.

Perhaps the first parameter parameter should have been defined as
"volatile void *s".

[...]

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#398999

FromDavid Brown <david.brown@hesbynett.no>
Date2026-05-15 10:20 +0200
Message-ID<10u6kvn$22lb$1@dont-email.me>
In reply to#398971
On 15/05/2026 00:55, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
> [...]
>> I have a feeling that I read somewhere about a proposed standard
>> library function that could be used to zero all padding bits and bytes
>> in a struct.  Unfortunately, I can't remember where I saw it - and
>> there is a fair chance it was a C++ proposal rather than a C proposal.
> 
> You're probably thinking of memset_explicit(), standardized in C23.

No, that's a different function for a different purpose.  But it could 
be used to clear all padding data in a struct - along with all 
non-padding data.  The point of this legendary function is that it only 
clears padding, not data fields.

The more I think about it, the more I am convinced it was for C++ - the 
natural interface there would be a template function that took a pointer 
to a struct.  I am not sure it if something like this would be feasible 
in C (except as a "magic" macro in the standard library).

> 
> N3220 7.26.6.2:
> 
>      The memset_explicit function copies the value of c (converted to an
>      unsigned char) into each of the first n characters of the object
>      pointed to by s. The purpose of this function is to make sensitive
>      information stored in the object inaccessible.
> 
> Footnote:
> 
>      The intention is that the memory store is always performed
>      (i.e. never elided), regardless of optimizations. This is in
>      contrast to calls to the memset function (7.26.6.1)
> 
> The only difference in the standard between the descriptions
> of memset() and memset_explicit() is the second sentence and
> the footnote.  I'm not convinced that that's enough to formally
> specify that an implementation that optimizes away a call to
> memset_explicit() is non-conforming.  But I think implementations
> will follow the intent.
> 
> Perhaps the first parameter parameter should have been defined as
> "volatile void *s".
> 

Yes, that would have made sense.

[toc] | [prev] | [next] | [standalone]


#398700

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-05-10 20:01 -0700
Message-ID<86jytar6n2.fsf@linuxsc.com>
In reply to#398672
highcrew <high.crew3868@fastmail.com> writes:

> Hello,
>
> I recently wrote a unit test, where I'm verifying that some array
> of data matches the expected value.  The comparison is done by looping
> on individual items, and invoking a comparison function for each of
> them.
>
>   struct item { long a, b;  in c; };
>   struct array { unsigned int n; struct item a[] }; // FAM
>
>   const struct item expected[] = {
>     {1, 2, 3},
>     {4, 5, 6},
>   };
>
>   struct array *actual = get(); // using calloc under the hood
>   assert(compare_array(expected, ARRSIZE(expected), actual) == 0);
>   free(actual);
>
> Oh, and I cheated on the comparison, thinking I could get away with a
> memcmp():
>
>   int compare(const struct item *a, const struct item *b)
>   {
>      return memcmp(a, b, sizeof *a);
>   }
>
> This test worked as intended under Debian (gcc 14.2.0), and failed under
> Alpine Linux (gcc 15.2.0.  But it works with clang).
>
> Why?  Because the padding of course.  It is OK in the `actual`
> array thanks to the fact I'm using `calloc()` under the hood, but it is
> not zero-initialized in `expected`, declared on the stack.
> The clean solution:  don't cheat nor assume padding is zeroed out, and
> write a proper comparison function.
>
> ...
>
> But then I started to wonder:  isn't a designated initializer
> supposed to wipe the memory?  I definitely seen that happen, but
> this is of course not saying it *must* happen.
>
> I can't find anything in the standard (I checked N3220).  I
> only found a mention of static and thread local objects, but
> nothing about objects declared on the stack.
>
> So, is the compiler only required to clear individual fields?
> Can it leave dirty memory on padding?  Or did I hit a compiler
> bug?

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.

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.

Point 2:  flexible array members do not participate in any
initialization.  Usually it's a mistake to declare a struct with a
flexible array member as an ordinary variable, but in any case there
is no way to use a declaration of a struct-with-fam to initialize
elements of the flexible array member.

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:

   union {
      unsigned char uca[ SUITABLE_SIZE ];
      struct array fam;
   } blah = { .uca = { 0 } };

   struct array *stuff = &blah.fam;

after which the variable 'stuff' can be used to refer to the zeroed
struct-with-flexible-array-member.  These two pieces can be combined
into one, like so:

   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.

[toc] | [prev] | [next] | [standalone]


#398710

Fromhighcrew <high.crew3868@fastmail.com>
Date2026-05-11 09:10 +0200
Message-ID<10trvca$topc$1@dont-email.me>
In reply to#398700
Hello,

On 5/11/26 5:01 AM, Tim Rentsch wrote:
> highcrew <high.crew3868@fastmail.com> 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.
Thanks!

> 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.

> 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]

- 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.

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

-- 
High Crew

[toc] | [prev] | [next] | [standalone]


#398819

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-05-12 09:36 -0700
Message-ID<86bjekmvom.fsf@linuxsc.com>
In reply to#398710
highcrew <high.crew3868@fastmail.com> writes:

> Hello,
>
> On 5/11/26 5:01 AM, Tim Rentsch wrote:
>
>> highcrew <high.crew3868@fastmail.com> 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 <stdio.h>

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.

[toc] | [prev] | [next] | [standalone]


#398730

Fromscott@slp53.sl.home (Scott Lurndal)
Date2026-05-11 15:34 +0000
Message-ID<VFmMR.786563$G7x8.308191@fx15.iad>
In reply to#398700
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>highcrew <high.crew3868@fastmail.com> writes:
>
>> Hello,
>>

>
>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:
>
>   union {
>      unsigned char uca[ SUITABLE_SIZE ];
>      struct array fam;
>   } blah = { .uca = { 0 } };
>
>   struct array *stuff = &blah.fam;

Or use memset(3) with the appropriate length.

[toc] | [prev] | [next] | [standalone]


#398790

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-05-11 18:23 -0700
Message-ID<86cxz1pgiq.fsf@linuxsc.com>
In reply to#398730
scott@slp53.sl.home (Scott Lurndal) writes:

> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>
>> highcrew <high.crew3868@fastmail.com> writes:
>>
>>> Hello,
>>>
>
>>
>> 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:
>>
>>   union {
>>      unsigned char uca[ SUITABLE_SIZE ];
>>      struct array fam;
>>   } blah = { .uca = { 0 } };
>>
>>   struct array *stuff = &blah.fam;
>
> Or use memset(3) with the appropriate length.

Part of the motivation of using a declarative and functional
formulation is being able to use it in an expressional,
rather than imperative, context.  The code shown above can
be used at file scope, which precludes the use of memset().

[toc] | [prev] | [next] | [standalone]


#398767

FromMichael S <already5chosen@yahoo.com>
Date2026-05-11 23:22 +0300
Message-ID<20260511232247.00006c5e@yahoo.com>
In reply to#398700
On Sun, 10 May 2026 20:01:53 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

> 
> 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.
> 

James Kuyper says that zeroing of padding is required by that standard.
I am not an expert in lawyer-style reading of the standard, but at my
level it looks that he is correct and the wording in unequivocal.
For example, n3220, 6.7.11:

11
If an object that has automatic storage duration is not initialized
explicitly, its representation is indeterminate. If an object that has
static or thread storage duration is not initialized explicitly, or
any object is initialized with an empty initializer, then it is subject
to default initialization, which initializes an object as follows:
— if it has pointer type, it is initialized to a null pointer;
— if it has decimal floating type, it is initialized to positive zero,
and the quantum exponent is implementation-defined;
— if it has arithmetic type, and it does not have decimal floating
type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively)
according to these rules, and any padding is initialized to zero bits;

[toc] | [prev] | [next] | [standalone]


#398779

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-05-11 14:34 -0700
Message-ID<10tti1a$1eenk$4@kst.eternal-september.org>
In reply to#398767
Michael S <already5chosen@yahoo.com> writes:
> On Sun, 10 May 2026 20:01:53 -0700
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>> 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.
>
> James Kuyper says that zeroing of padding is required by that standard.
> I am not an expert in lawyer-style reading of the standard, but at my
> level it looks that he is correct and the wording in unequivocal.
> For example, n3220, 6.7.11:
>
> 11
> If an object that has automatic storage duration is not initialized
> explicitly, its representation is indeterminate. If an object that has
> static or thread storage duration is not initialized explicitly, or
> any object is initialized with an empty initializer, then it is subject
> to default initialization, which initializes an object as follows:
> — if it has pointer type, it is initialized to a null pointer;
> — if it has decimal floating type, it is initialized to positive zero,
> and the quantum exponent is implementation-defined;
> — if it has arithmetic type, and it does not have decimal floating
> type, it is initialized to (positive or unsigned) zero;
> — if it is an aggregate, every member is initialized (recursively)
> according to these rules, and any padding is initialized to zero bits;

That applies only to objects with static storage duration *without*
an initializer (or with an empty initializer {}, a new feature
in C23).  It doesn't imply that if there is an initializer, padding
is zeroed.

If you want to set *some* members to non-zero values and guarantee
zero for other members and all-bits-zero for padding, there's
no direct way to do it.  You could initialize an object with {}
(or {0} pre-C23) and then assign values to the desired members.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#398780

FromMichael S <already5chosen@yahoo.com>
Date2026-05-12 00:55 +0300
Message-ID<20260512005524.000052a9@yahoo.com>
In reply to#398779
On Mon, 11 May 2026 14:34:34 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

> Michael S <already5chosen@yahoo.com> writes:
> > On Sun, 10 May 2026 20:01:53 -0700
> > Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:  
> >> 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.  
> >
> > James Kuyper says that zeroing of padding is required by that
> > standard. I am not an expert in lawyer-style reading of the
> > standard, but at my level it looks that he is correct and the
> > wording in unequivocal. For example, n3220, 6.7.11:
> >
> > 11
> > If an object that has automatic storage duration is not initialized
> > explicitly, its representation is indeterminate. If an object that
> > has static or thread storage duration is not initialized
> > explicitly, or any object is initialized with an empty initializer,
> > then it is subject to default initialization, which initializes an
> > object as follows: — if it has pointer type, it is initialized to a
> > null pointer; — if it has decimal floating type, it is initialized
> > to positive zero, and the quantum exponent is
> > implementation-defined; — if it has arithmetic type, and it does
> > not have decimal floating type, it is initialized to (positive or
> > unsigned) zero; — if it is an aggregate, every member is
> > initialized (recursively) according to these rules, and any padding
> > is initialized to zero bits;  
> 
> That applies only to objects with static storage duration *without*
> an initializer (or with an empty initializer {}, a new feature
> in C23).  It doesn't imply that if there is an initializer, padding
> is zeroed.
> 
> If you want to set *some* members to non-zero values and guarantee
> zero for other members and all-bits-zero for padding, there's
> no direct way to do it.  You could initialize an object with {}
> (or {0} pre-C23) and then assign values to the desired members.
> 

In this draft it is less clear. Let's look at N2310,6.7.9:

On one hand, we have 10+19:

If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.
If an object that has static or thread storage duration is not
initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or
unsigned) zero;
— if it is an aggregate, every member is initialized (recursively)
according to these rules, and any padding is initialized to zero bits;
— if it is a union, the first named member is initialized (recursively)
according to these rules, and any padding is initialized to zero bits;


The initialization shall occur in initializer list order, each
initializer provided for a particular subobject overriding any
previously listed initializer for the same subobject) all subobjects
that are not initialized explicitly shall be initialized implicitly the
same as objects that have static storage duration.

It sounds like zeroing of padding is required.


On the other hand, we have 9:
Except where explicitly stated otherwise, for the purposes of this
subclause unnamed members of objects of structure and union type do not
participate in initialization. Unnamed members of structure objects
have indeterminate value even after initialization.

It sounds like zeroing of padding is not required.

It's quite confusing.






[toc] | [prev] | [next] | [standalone]


#398784

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-05-11 15:27 -0700
Message-ID<86pl31poow.fsf@linuxsc.com>
In reply to#398780
Michael S <already5chosen@yahoo.com> writes:

> On Mon, 11 May 2026 14:34:34 -0700
> Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>
>> Michael S <already5chosen@yahoo.com> writes:
>>
>>> On Sun, 10 May 2026 20:01:53 -0700
>>> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>>>
>>>> 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.
>>>
>>> James Kuyper says that zeroing of padding is required by that
>>> standard.  I am not an expert in lawyer-style reading of the
>>> standard, but at my level it looks that he is correct and the
>>> wording in unequivocal.  For example, n3220, 6.7.11:
>>>
>>> 11
>>> If an object that has automatic storage duration is not initialized
>>> explicitly, its representation is indeterminate.  If an object that
>>> has static or thread storage duration is not initialized
>>> explicitly, or any object is initialized with an empty initializer,
>>> then it is subject to default initialization, which initializes an
>>> object as follows: ? if it has pointer type, it is initialized to a
>>> null pointer; ? if it has decimal floating type, it is initialized
>>> to positive zero, and the quantum exponent is
>>> implementation-defined; ? if it has arithmetic type, and it does
>>> not have decimal floating type, it is initialized to (positive or
>>> unsigned) zero; ? if it is an aggregate, every member is
>>> initialized (recursively) according to these rules, and any padding
>>> is initialized to zero bits;
>>
>> That applies only to objects with static storage duration *without*
>> an initializer (or with an empty initializer {}, a new feature
>> in C23).  It doesn't imply that if there is an initializer, padding
>> is zeroed.
>>
>> If you want to set *some* members to non-zero values and guarantee
>> zero for other members and all-bits-zero for padding, there's
>> no direct way to do it.  You could initialize an object with {}
>> (or {0} pre-C23) and then assign values to the desired members.
>
> In this draft it is less clear.  Let's look at N2310,6.7.9:
>
> On one hand, we have 10+19:
>
> If an object that has automatic storage duration is not initialized
> explicitly, its value is indeterminate.
> If an object that has static or thread storage duration is not
> initialized explicitly, then:
> ? if it has pointer type, it is initialized to a null pointer;
> ? if it has arithmetic type, it is initialized to (positive or
> unsigned) zero;
> ? if it is an aggregate, every member is initialized (recursively)
> according to these rules, and any padding is initialized to zero bits;
> ? if it is a union, the first named member is initialized (recursively)
> according to these rules, and any padding is initialized to zero bits;
>
>
> The initialization shall occur in initializer list order, each
> initializer provided for a particular subobject overriding any
> previously listed initializer for the same subobject) all subobjects
> that are not initialized explicitly shall be initialized implicitly the
> same as objects that have static storage duration.
>
> It sounds like zeroing of padding is required.
>
>
> On the other hand, we have 9:
> Except where explicitly stated otherwise, for the purposes of this
> subclause unnamed members of objects of structure and union type do not
> participate in initialization.  Unnamed members of structure objects
> have indeterminate value even after initialization.
>
> It sounds like zeroing of padding is not required.
>
> It's quite confusing.

Padding and unnamed members are different things.  All members,
including unnamed members, have a type.  Padding doesn't have
a type.

See also my other response.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web