summaryrefslogtreecommitdiff
path: root/devdocs/c/language%2Fstruct_initialization.html
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2024-04-07 13:41:34 -0500
committerCraig Jennings <c@cjennings.net>2024-04-07 13:41:34 -0500
commit754bbf7a25a8dda49b5d08ef0d0443bbf5af0e36 (patch)
treef1190704f78f04a2b0b4c977d20fe96a828377f1 /devdocs/c/language%2Fstruct_initialization.html
new repository
Diffstat (limited to 'devdocs/c/language%2Fstruct_initialization.html')
-rw-r--r--devdocs/c/language%2Fstruct_initialization.html125
1 files changed, 125 insertions, 0 deletions
diff --git a/devdocs/c/language%2Fstruct_initialization.html b/devdocs/c/language%2Fstruct_initialization.html
new file mode 100644
index 00000000..f97f90ae
--- /dev/null
+++ b/devdocs/c/language%2Fstruct_initialization.html
@@ -0,0 +1,125 @@
+ <h1 id="firstHeading" class="firstHeading">Struct and union initialization</h1> <p>When <a href="initialization" title="c/language/initialization">initializing</a> an object of <a href="struct" title="c/language/struct">struct</a> or <a href="union" title="c/language/union">union</a> type, the initializer must be a <span class="t-rev-inl t-until-c23"><span>non-empty,</span><span><span class="t-mark-rev t-until-c23">(until C23)</span></span></span> brace-enclosed, comma-separated list of initializers for the members:</p>
+<table class="t-sdsc-begin"> <tr class="t-sdsc"> <td> <code>=</code> <code>{</code> <span class="t-spar">expression</span> <code>,</code> <code>...</code> <code>}</code> </td> <td> (1) </td> <td> <span class="t-mark-rev t-until-c99">(until C99)</span> </td>
+</tr> <tr class="t-sdsc"> <td> <code>=</code> <code>{</code> <span class="t-spar">designator</span><span class="t-mark">(optional)</span> <span class="t-spar">expression</span> <code>,</code> <code>...</code> <code>}</code> </td> <td> (2) </td> <td> <span class="t-mark-rev t-since-c99">(since C99)</span> </td>
+</tr> <tr class="t-sdsc"> <td> <code>=</code> <code>{</code> <code>}</code> </td> <td> (3) </td> <td> <span class="t-mark-rev t-since-c23">(since C23)</span> </td>
+</tr>
+</table> <p>where the <span class="t-spar">designator</span> is a sequence (whitespace-separated or adjacent) of individual member designators of the form <code>.</code> <span class="t-spar">member</span> and <a href="array_initialization" title="c/language/array initialization">array designators</a> of the form <code>[</code> <span class="t-spar">index</span> <code>]</code>.</p>
+<p>All members that are not initialized explicitly are <a href="initialization#Empty_initialization" title="c/language/initialization">empty-initialized</a>.</p>
+<h3 id="Explanation"> Explanation</h3> <p>When initializing a <a href="union" title="c/language/union">union</a>, the initializer list must have only one member, which initializes the first member of the union<span class="t-rev-inl t-since-c99"><span> unless a designated initializer is used</span><span><span class="t-mark-rev t-since-c99">(since C99)</span></span></span>.</p>
+<div class="c source-c"><pre data-language="c">union { int x; char c[4]; }
+ u = {1}, // makes u.x active with value 1
+ u2 = { .c={'\1'} }; // makes u2.c active with value {'\1','\0','\0','\0'}</pre></div> <p>When initializing a <a href="struct" title="c/language/struct">struct</a>, the first initializer in the list initializes the first declared member<span class="t-rev-inl t-since-c99"><span> (unless a designator is specified)</span><span><span class="t-mark-rev t-since-c99">(since C99)</span></span></span>, and all subsequent initializers <span class="t-rev-inl t-since-c99"><span>without designators </span><span><span class="t-mark-rev t-since-c99">(since C99)</span></span></span>initialize the struct members declared after the one initialized by the previous expression.</p>
+<div class="c source-c"><pre data-language="c">struct point {double x,y,z;} p = {1.2, 1.3}; // p.x=1.2, p.y=1.3, p.z=0.0
+div_t answer = {.quot = 2, .rem = -1 }; // order of elements in div_t may vary</pre></div> <table class="t-rev-begin"> <tr class="t-rev t-since-c99">
+<td> <p>A designator causes the following initializer to initialize the struct member described by the designator. Initialization then continues forward in order of declaration, beginning with the next element declared after the one described by the designator.</p>
+<div class="c source-c"><pre data-language="c">struct {int sec,min,hour,day,mon,year;} z
+ = {.day=31,12,2014,.sec=30,15,17}; // initializes z to {30,15,17,31,12,2014}</pre></div> </td> <td><span class="t-mark-rev t-since-c99">(since C99)</span></td>
+</tr> </table> <p>It's an error to provide more initializers than members.</p>
+<h3 id="Nested_initialization"> Nested initialization</h3> <p>If the members of the struct or union are arrays, structs, or unions, the corresponding initializers in the brace-enclosed list of initializers are any initializers that are valid for those members, except that their braces may be omitted as follows:</p>
+<p>If the nested initializer begins with an opening brace, the entire nested initializer up to its closing brace initializes the corresponding member object. Each left opening brace establishes a new <i>current object</i>. The members of the current object are initialized in their natural order<span class="t-rev-inl t-since-c99"><span>, unless designators are used</span><span><span class="t-mark-rev t-since-c99">(since C99)</span></span></span>: array elements in subscript order, struct members in declaration order, only the first declared member of any union. The subobjects within the current object that are not explicitly initialized by the closing brace are <a href="initialization#Empty_initialization" title="c/language/initialization">empty-initialized</a>.</p>
+<div class="c source-c"><pre data-language="c">struct example {
+ struct addr_t {
+ uint32_t port;
+ } addr;
+ union {
+ uint8_t a8[4];
+ uint16_t a16[2];
+ } in_u;
+};
+struct example ex = { // start of initializer list for struct example
+ { // start of initializer list for ex.addr
+ 80 // initialized struct's only member
+ }, // end of initializer list for ex.addr
+ { // start of initializer-list for ex.in_u
+ {127,0,0,1} // initializes first element of the union
+ } };</pre></div> <p>If the nested initializer does not begin with an opening brace, only enough initializers from the list are taken to account for the elements or members of the member array, struct or union; any remaining initializers are left to initialize the next struct member:</p>
+<div class="c source-c"><pre data-language="c">struct example ex = {80, 127, 0, 0, 1}; // 80 initializes ex.addr.port
+ // 127 initializes ex.in_u.a8[0]
+ // 0 initializes ex.in_u.a8[1]
+ // 0 initializes ex.in_u.a8[2]
+ // 1 initializes ex.in_u.a8[3]</pre></div> <table class="t-rev-begin"> <tr class="t-rev t-since-c99">
+<td> <p>When designators are nested, the designators for the members follow the designators for the enclosing structs/unions/arrays. Within any nested bracketed initializer list, the outermost designator refers to the <i>current object</i> and selects the subobject to be initialized within the <i>current object</i> only.</p>
+<div class="c source-c"><pre data-language="c">struct example ex2 = { // current object is ex2, designators are for members of example
+ .in_u.a8[0]=127, 0, 0, 1, .addr=80};
+struct example ex3 = {80, .in_u={ // changes current object to the union ex.in_u
+ 127,
+ .a8[2]=1 // this designator refers to the member of in_u
+ } };</pre></div> <p>If any subobject is explicitly initialized twice (which may happen when designators are used), the initializer that appears later in the list is the one used (the earlier initializer may not be evaluated):</p>
+<div class="c source-c"><pre data-language="c">struct {int n;} s = {printf("a\n"), // this may be printed or skipped
+ .n=printf("b\n")}; // always printed</pre></div> <p>Although any non-initialized subobjects are initialized implicitly, implicit initialization of a subobject never overrides explicit initialization of the same subobject if it appeared earlier in the initializer list (choose clang to observe the correct output):</p>
+<div class="c source-c"><pre data-language="c">#include &lt;stdio.h&gt;
+typedef struct { int k; int l; int a[2]; } T;
+typedef struct { int i; T t; } S;
+T x = {.l = 43, .k = 42, .a[1] = 19, .a[0] = 18 };
+ // x initialized to {42, 43, {18, 19} }
+int main(void)
+{
+ S l = { 1, // initializes l.i to 1
+ .t = x, // initializes l.t to {42, 43, {18, 19} }
+ .t.l = 41, // changes l.t to {42, 41, {18, 19} }
+ .t.a[1] = 17 // changes l.t to {42, 41, {18, 17} }
+ };
+ printf("l.t.k is %d\n", l.t.k); // .t = x sets l.t.k to 42 explicitly
+ // .t.l = 41 would zero out l.t.k implicitly
+}</pre></div> <p>Output:</p>
+<div class="text source-text"><pre data-language="c">l.t.k is 42</pre></div> <p>However, when an initializer begins with a left open brace, its <i>current object</i> is fully re-initialized and any prior explicit initializers for any of its subobjects are ignored:</p>
+<div class="c source-c"><pre data-language="c">struct fred { char s[4]; int n; };
+struct fred x[ ] = { { { "abc" }, 1 }, // inits x[0] to { {'a','b','c','\0'}, 1 }
+ [0].s[0] = 'q' // changes x[0] to { {'q','b','c','\0'}, 1 }
+ };
+struct fred y[ ] = { { { "abc" }, 1 }, // inits y[0] to { {'a','b','c','\0'}, 1 }
+ [0] = { // current object is now the entire y[0] object
+ .s[0] = 'q'
+ } // replaces y[0] with { {'q','\0','\0','\0'}, 0 }
+ };</pre></div> </td> <td><span class="t-mark-rev t-since-c99">(since C99)</span></td>
+</tr> </table> <h3 id="Notes"> Notes</h3> <p>The initializer list may have a trailing comma, which is ignored.</p>
+<div class="c source-c"><pre data-language="c">struct {double x,y;} p = {1.0,
+ 2.0, // trailing comma OK
+ };</pre></div> <table class="t-rev-begin"> <tr class="t-rev t-until-c23">
+<td> <p>In C, the braced list of initializers cannot be empty (note that C++ allows empty lists, and also note that a <a href="struct" title="c/language/struct">struct</a> in C cannot be empty):</p>
+</td> <td><span class="t-mark-rev t-until-c23">(until C23)</span></td>
+</tr> <tr class="t-rev t-since-c23">
+<td> <p>The initializer list can be empty in C as in C++:</p>
+</td> <td><span class="t-mark-rev t-since-c23">(since C23)</span></td>
+</tr> </table> <div class="c source-c"><pre data-language="c">struct {int n;} s = {0}; // OK
+struct {int n;} s = {}; // Error until C23: initializer-list cannot be empty
+ // OK since C23: s.n is initialized to 0
+struct {} s = {}; // Error: struct cannot be empty</pre></div> <table class="t-rev-begin"> <tr class="t-rev t-until-c99">
+<td> <p>Every expression in the initializer list must be a <a href="constant_expression" title="c/language/constant expression">constant expression</a> when initializing aggregates of any storage duration.</p>
+</td> <td><span class="t-mark-rev t-until-c99">(until C99)</span></td>
+</tr> <tr class="t-rev t-since-c99">
+<td> <p>As with all other <a href="initialization" title="c/language/initialization">initialization</a>, every expression in the initializer list must be a <a href="constant_expression" title="c/language/constant expression">constant expression</a> when initializing aggregates of static<span class="t-rev-inl t-since-c11"><span> or thread-local</span><span><span class="t-mark-rev t-since-c11">(since C11)</span></span></span> <a href="storage_duration" title="c/language/storage duration">storage duration</a>:</p>
+<div class="c source-c"><pre data-language="c">static struct {char* p} s = {malloc(1)}; // error</pre></div> <p>The <a href="eval_order" title="c/language/eval order">order of evaluation</a> of the subexpressions in any initializer is indeterminately sequenced (but not in C++ since C++11):</p>
+<div class="c source-c"><pre data-language="c">int n = 1;
+struct {int x,y;} p = {n++, n++}; // unspecified, but well-defined behavior:
+ // n is incremented twice in arbitrary order
+ // p equal {1,2} and {2,1} are both valid</pre></div> </td> <td><span class="t-mark-rev t-since-c99">(since C99)</span></td>
+</tr> </table> <h3 id="Example"> Example</h3> <div class="t-example"> <div class="c source-c"><pre data-language="c">#include &lt;stdio.h&gt;
+#include &lt;time.h&gt;
+
+int main(void)
+{
+ char buff[70];
+ // designated initializers simplify the use of structs whose
+ // order of members is unspecified
+ struct tm my_time = { .tm_year=2012-1900, .tm_mon=9, .tm_mday=9,
+ .tm_hour=8, .tm_min=10, .tm_sec=20 };
+ strftime(buff, sizeof buff, "%A %c", &amp;my_time);
+ puts(buff);
+}</pre></div> <p>Possible output:</p>
+<div class="text source-text"><pre data-language="c">Sunday Sun Oct 9 08:10:20 2012</pre></div> </div> <h3 id="References"> References</h3> <ul>
+<li> C17 standard (ISO/IEC 9899:2018): </li>
+<ul><li> 6.7.9/12-39 Initialization (p: 101-105) </li></ul>
+<li> C11 standard (ISO/IEC 9899:2011): </li>
+<ul><li> 6.7.9/12-38 Initialization (p: 140-144) </li></ul>
+<li> C99 standard (ISO/IEC 9899:1999): </li>
+<ul><li> 6.7.8/12-38 Initialization (p: 126-130) </li></ul>
+<li> C89/C90 standard (ISO/IEC 9899:1990): </li>
+<ul><li> 6.5.7 Initialization </li></ul>
+</ul> <h3 id="See_also"> See also</h3> <table class="t-dsc-begin"> <tr class="t-dsc"> <td colspan="2"> <span><a href="https://en.cppreference.com/w/cpp/language/aggregate_initialization" title="cpp/language/aggregate initialization">C++ documentation</a></span> for <span class=""><span>Aggregate initialization</span></span> </td>
+</tr> </table> <div class="_attribution">
+ <p class="_attribution-p">
+ &copy; cppreference.com<br>Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.<br>
+ <a href="https://en.cppreference.com/w/c/language/struct_initialization" class="_attribution-link">https://en.cppreference.com/w/c/language/struct_initialization</a>
+ </p>
+</div>