648

I want to initialize a struct element, split in declaration and initialization. This is what I have:

typedef struct MY_TYPE {
  bool flag;
  short int value;
  double stuff;
} MY_TYPE;

void function(void) {
  MY_TYPE a;
  ...
  a = { true, 15, 0.123 }
}

Is this the way to declare and initialize a local variable of MY_TYPE in accordance with C programming language standards (C89, C90, C99, C11, etc.)? Or is there anything better or at least working?

Update I ended up having a static initialization element where I set every subelement according to my needs.

7
  • 3
    you really should accept a better answer, I see you had to use some bad coding guide, but you still shouldn't suggest to other people that that is the right way to do it.. Commented Jul 28, 2012 at 9:43
  • @KarolyHorvath well, most of the good answers are specific to C99. Maybe my question is a duplicate of stackoverflow.com/questions/6624975/… ? Commented Jul 29, 2012 at 10:02
  • if that was your original intention, then probably yes, but then 1) the votes would be very misleading. 2) from the top search hits this is the only one which shows the C99 way..... it would be better to re-use this page for C99 demonstration... (apparently people started to link this page to show how to do it) Commented Jul 29, 2012 at 11:02
  • 16
    Interesting that the accepted (and heavily upvoted) answer doesn't actually answer the question, even as originally posted. Designated initializers don't address the OP's problem, which is to split the declaration from the initialization. For pre-1999 C, the only real solution is to assign to each member; for C99 and later, a compound literal, as in CesarB's answer, is the solution. (Of course an actual initializer, with or without designators, would be even better, but apparently the OP was saddled with a really bad coding standard.) Commented Jun 9, 2013 at 6:39
  • 39
    Strictly speaking, the term "ANSI C" now refers to the 2011 ISO standard, which ANSI has adopted. But in practice the term "ANSI C" commonly refers to the (officially obsolete) 1989 standard. For example, "gcc -ansi" still enforces the 1989 standard. Since it's ISO that published the 1990, 1999, and 2011 standards, it's best to avoid the term "ANSI C", and to refer to the date of the standard if there's any possibility of confusion. Commented Jun 9, 2013 at 6:43

18 Answers 18

1034

In C99, you can use a designated initializer to initialize a structure:

MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 };

Other members are initialized as zero: "Omitted field members are implicitly initialized the same as objects that have static storage duration." (https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html)

Sign up to request clarification or add additional context in comments.

9 Comments

awesome, thanks. you can even nest em: static oxeRay2f ray = { .unitDir = { .x = 1.0f, .y = 0.0f } };
This doesn't answer the question at all. OP wants to separate the initialization from the declaration.
C99 != ANSI C - So this doesn't work in C89, nor in C90.
C99 is ANSI C, see this
@CutbertoOcampo I understand what happened now. The original question was asking for solutions in ANSI C, obviously he wanted answers for C89 only. In 2016 the question was edited and "ANSI C" was removed, which now makes it hard to understand why this answer and comments mention "(ANSI) C99".
|
278

You can do it with a compound literal. According to that page, it works in C99 (which also counts as ANSI C).

MY_TYPE a;

a = (MY_TYPE) { .flag = true, .value = 123, .stuff = 0.456 };
...
a = (MY_TYPE) { .value = 234, .stuff = 1.234, .flag = false };

The designations in the initializers are optional; you could also write:

a = (MY_TYPE) { true,  123, 0.456 };
...
a = (MY_TYPE) { false, 234, 1.234 };

5 Comments

So, designated initializers are for when you declare and define at the same time, but compound literals are for when you define an already-declared variable?
@Geremia you have to first define the struct in both cases, but with designated initializers, you make the code more readable, and more resilient to errors, in case of changes in the struct.
This is a little tricky. Many times (some successful) I have tried to use designated initializers. However, it only has now become clear (thanks to your and @philant's example) that there must exist a cast if the initializer is not used at the time of object creation. However, I have now also learned that if initializers are used at a time other than object creation (as in your example) then it is referred to as a compound literal, not strictly a designated initializer. ideone.com/Ze3rnZ
Just as a clarification on the comment from @sherrellbc above, if "initializers are used at a time other than object creation" then they are not initializers. Initialization takes place at the same time as definition; any value change at another time is assignment, not initialization. So a designated initializer can be used only for initialization, whereas a compound literal can only be used for assignment. The syntax is slightly different as well because the compound literal always requires a cast.
The difference between initialization and assignment is important in the context of const (where assignment is not possible but initialization is) and static (static locals are initialized only once, at the time of creation).
122

I see you've already received an answer about ANSI C 99, so I'll throw a bone about ANSI C 89. ANSI C 89 allows you to initialize a struct this way:

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = { 5, 2.2, "George" };
    return 0;
}

An important thing to remember, at the moment you initialize even one object/ variable in the struct, all of its other variables will be initialized to default value.

If you don't initialize the values in your struct, all variables will contain "garbage values".

3 Comments

Is it possible to use variables in the initialization ?
@Cyan It is for objects with automatic storage duration. See 6.7.9 13) in open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf . For global objects is pretty much restricted to literals. You can't even use other global objects, even if they're const.
So the only difference with C 99 is that you can't specify the designations?
53

a = (MYTYPE){ true, 15, 0.123 };

would do fine in C99

To initialize during a declaration:

MYTYPE a = { true, 15, 0.123 };

1 Comment

Just what I was looking for; thank you. As a more complete answer, would as be nice to include initialization of a struct during declaration.
35

Adding to All of these good answer a summary to how to initialize a structure (union and Array) in C, focused especially on the Designed Initializer.

Standard Initialization

struct point 
{
    double x;
    double y;
    double z;
}

p = {1.2, 1.3}; 

Designated Initializer

The Designated Initializer came up since the ISO C99 and is a different and more dynamic way to initialize in C when initializing struct, union or an array.

The biggest difference to standard initialization is that you don't have to declare the elements in a fixed order and you can also omit element.

From The GNU Guide:

Standard C90 requires the elements of an initializer to appear in a fixed order, the same as the order of the elements in the array or structure being initialized.

In ISO C99 you can give the elements in random order, specifying the array indices or structure field names they apply to, and GNU C allows this as an extension in C90 mode as well


Examples

1. Array Index

Standard Initialization

int a[6] = { 0, 0, 15, 0, 29, 0 };

Designated Initialization

int a[6] = {[4] = 29, [2] = 15 }; // or
int a[6] = {[4]29 , [2]15 }; // or
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };

2. Struct or union:

Standard Initialization

struct point { int x, y; };

Designated Initialization

struct point p = { .y = 2, .x = 3 }; or
struct point p = { y: 2, x: 3 };

3. Combine naming elements with ordinary C initialization of successive elements:

Standard Initialization

int a[6] = { 0, v1, v2, 0, v4, 0 };

Designated Initialization

int a[6] = { [1] = v1, v2, [4] = v4 };

4. Others:

Labeling the elements of an array initializer

int whitespace[256] = { [' '] = 1, ['\t'] = 1, ['\h'] = 1,
                        ['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };

write a series of ‘.fieldname’ and ‘[index]’ designators before an ‘=’ to specify a nested subobject to initialize

struct point ptarray[10] = { [2].y = yv2, [2].x = xv2, [0].x = xv0 };

Guides

2 Comments

struct point { int x, y; }; under 2. Struct or union titled with Standard Initialization is not an initialization. It is the definition of the type struct point. There is not even memory allocated yet. With the code titled "Designated Initialization" a variable of type struct point is then declared (as p) and initialized (with p.y = 2, p.x = 3) at once. After that we have allocated and initialized memory plus a name (p) for this bit of memory.
The code titled "Labeling the elements of an array" does not "label" elements, it picks elements to initialize (which is stated correctly below the code). If you want, the elements are already labelled with int whitespace[256];. There are now 256 elements labelled with 0, 1, 2, ..., 255. It just so happens that the characters ' ', '\t', '\h', ... (of type char) are implicitly casted to int where they would be written as 32, 9, 92, 104, 12, 10, 13. So there are 7 elements picked of the 256 which are initialized with 1, the other 249 elements are implicitly initialized with 0.
26

C programming language standard ISO/IEC 9899:1999 (commonly known as C99) allows one to use a designated initializer to initialize members of a structure or union as follows:

MY_TYPE a = { .stuff = 0.456, .flag = true, .value = 123 };

It is defined in paragraph 7, section 6.7.8 Initialization of ISO/IEC 9899:1999 standard as:

If a designator has the form
. identifier
then the current object (defined below) shall have structure or union type and the identifier shall be the name of a member of that type.

Note that paragraph 9 of the same section states that:

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.

In GNU GCC implementation however omitted members are initialized as zero or zero-like type-appropriate value. As stated in section 6.27 Designated Initializers of GNU GCC documentation:

Omitted field members are implicitly initialized the same as objects that have static storage duration.

Microsoft Visual C++ compiler should support designated initializers since version 2013 according to official blog post C++ Conformance Roadmap. Paragraph Initializing unions and structs of Initializers article at MSDN Visual Studio documentation suggests that unnamed members initialized to zero-like appropriate values similarly to GNU GCC.

ISO/IEC 9899:2011 standard (commonly known as C11) which had superseded ISO/IEC 9899:1999 retains designated initializers under section 6.7.9 Initialization. It also retains paragraph 9 unchanged.

New ISO/IEC 9899:2018 standard (commonly known as C18) which had superseded ISO/IEC 9899:2011 retains designated initializers under section 6.7.9 Initialization. It also retains paragraph 9 unchanged.

2 Comments

I believe "Unnamed member" doesn't mean "omitted fields", but rather "anonymous members" such as the union in struct thing { union { char ch; int i; }; };. The standard later says: "If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array,the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration."
"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." And then then explicitly stated otherwise further down (C17): "If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration."
25

You've almost got it...

MY_TYPE a = { true, 15, 0.123 };

Quick search on 'struct initialize c' shows me this

4 Comments

I think this is true for standard C, but not for ANSI C(99?). Also I'm bound to coding rules that won't allow me to do declaration and initialization at once, so I have to split it up and initialize every single subelement.
Initialization can only happen at the point of declaration. That is what it means to 'initialize'. Otherwise you're allowing an undefined value to be the inital value of your variable / struct, and then assigning a value later.
um... You have coding rules that are deliberately bad? Perhaps you should introduce the guy who wrote them to "Resource Acquisition Is Initialization" (en.wikipedia.org/wiki/RAII)
Trust me, I really, really, can't change a bit of this rules at this point. It feels horrible to code it. And there are a lot of other rules right out of the 70s, like static code headers with management information like Revision number. Changes for every release, even if the source didn't change...
18

as Ron Nuni said:

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = {5, 2.2, "George"};
    return 0;
}

An important thing to remember: at the moment you initialize even one object/variable in the struct, all of its other variables will be initialized to default value.

If you don't initialize the values in your struct (i.e. if you just declare that variable), all variable.members will contain "garbage values", only if the declaration is local!

If the declaration is global or static (like in this case), all uninitialized variable.members will be initialized automatically to:

  • 0 for integers and floating point
  • '\0' for char (of course this is just the same as 0, and char is an integer type)
  • NULL for pointers.

1 Comment

Interesting about the local/global, this also applies to struct tm time values. I had a local one and in one case DST was on, in another it wasn't, not due to anything I did. I wasn't using DST (the tm_isdst field), this was from strptime, but when I converted to time_t some were an hour off.
6

This can be done in different ways:

MY_TYPE a = { true, 1, 0.1 };

MY_TYPE a = { .stuff = 0.1, .flag = true, .value = 1 }; //designated initializer, not available in c++

MY_TYPE a;
a = (MY_TYPE) { true,  1, 0.1 };

MY_TYPE m (true, 1, 0.1); //works in C++, not available in C

Also, you can define member while declaring structure.

#include <stdio.h>

struct MY_TYPE
{
    int a;
    int b;
}m = {5,6};

int main()
{
    printf("%d  %d\n",m.a,m.b);    
    return 0;
}

Comments

5

I didn't like any of these answers so I made my own. I don't know if this is ANSI C or not, it's just GCC 4.2.1 in it's default mode. I never can remember the bracketing so I start with a subset of my data and do battle with compiler error messages until it shuts up. Readability is my first priority.

// in a header:
typedef unsigned char uchar;

struct fields {
  uchar num;
  uchar lbl[35];
};

// in an actual c file (I have 2 in this case)
struct fields labels[] = {
  {0, "Package"},
  {1, "Version"},
  {2, "Apport"},
  {3, "Architecture"},
  {4, "Bugs"},
  {5, "Description-md5"},
  {6, "Essential"},
  {7, "Filename"},
  {8, "Ghc-Package"},
  {9, "Gstreamer-Version"},
  {10, "Homepage"},
  {11, "Installed-Size"},
  {12, "MD5sum"},
  {13, "Maintainer"},
  {14, "Modaliases"},
  {15, "Multi-Arch"},
  {16, "Npp-Description"},
  {17, "Npp-File"},
  {18, "Npp-Name"},
  {19, "Origin"}
};

The data may start life as a tab-delimited file that you search-replace to massage into something else. Yes, this is Debian stuff. So one outside pair of {} (indicating the array), then another pair for each struct inside. With commas between. Putting things in a header isn't strictly necessary, but I've got about 50 items in my struct so I want them in a separate file, both to keep the mess out of my code and so it's easier to replace.

3 Comments

There were no question about initialization of array of structures! I mean, your answer contains overhead.
I guess my point was declaring the struct with values already in it vs. using = to set each value later.
That principle applies whether it's one struct or an array of them. Using = isn't really initialization, I wouldn't think.
3

If MS has not updated to C99, MY_TYPE a = { true,15,0.123 };

1 Comment

Nobody asked (or cares) about the MSVC compiler. 9 years later after this answer was posted and they still haven't managed full C99 compliance.
2
void function(void) {
  MY_TYPE a;
  a.flag = true;
  a.value = 15;
  a.stuff = 0.123;
}

2 Comments

once i've heard 'initialization is different than assignment'. so isn't this an assignment rather than initialization?
Indeed this is not initialization so it does not answer the question.
2

I found another way to initialize structs.

The struct:

typedef struct test {
    int num;
    char* str;
} test;

Initialization:

test tt = {
    num: 42,
    str: "nice"
};

As per GCC’s documentation, this syntax is obsolete since GCC 2.5.

1 Comment

Why post an answer in 2015 demonstrating something which had been obsolete for some 20 years at the point when this answer was posted?
1

Structure in C can be declared and initialized like this:

typedef struct book
{
    char title[10];
    char author[10];
    float price;
} book;

int main() {
    book b1={"DS", "Ajay", 250.0};

    printf("%s \t %s \t %f", b1.title, b1.author, b1.price);

    return 0;
}

Comments

1

Another cool way to initialize structure members in C is to use the colon syntax. The following is how you can do it.

MY_TYPE a = {flag:true, value:123, stuff:0.456};

2 Comments

warning: use of GNU old-style field designator extension
It is not "cool", it is obsolete and non-standard C which went outdated in the 1990s even for programs accepting non-standard C. It is not something you should be teaching people to use in year 2024 and not before that either.
0

I have read the Microsoft Visual Studio 2015 Documentation for Initializing Aggregate Types yet, all forms of initializing with {...} are explained there, but the initializing with dot, named ''designator'' isn't mentioned there. It does not work also.

The C99 standard chapter 6.7.8 Initialization explains the possibility of designators, but in my mind it is not really clear for complex structs. The C99 standard as pdf .

In my mind, it may be better to

  1. Use the = {0};-initialization for all static data. It is less effort for the machine code.
  2. Use macros for initializing, for example

    typedef MyStruct_t{ int x, int a, int b; } MyStruct; define INIT_MyStruct(A,B) { 0, A, B}

The macro can be adapted, its argument list can be independent of changed struct content. It is proper if less elements should be initialized. It is also proper for nested struct. 3. A simple form is: Initialize in a subroutine:

void init_MyStruct(MyStruct* thiz, int a, int b) {
  thiz->a = a; thiz->b = b; }

This routine looks like ObjectOriented in C. Use thiz, not this to compile it with C++ too!

MyStruct data = {0}; //all is zero!
init_MyStruct(&data, 3, 456);

1 Comment

"but the initializing with dot, named ''designator'' isn't mentioned there" That's because the Microsoft C compiler is horribly outdated, non-standard and irrelevant in general. Using macros for basic stuff like this is bad advice. Furthermore what you describe is assignment, not initialization.
0

Here follows a more detailed answer for those who like a bit more insight in the language mechanics related to array/struct initialization.

Initialization versus assignment
First of all it is important to know the difference between initialization and assignment. Both are done using one of the assignment operators, most commonly the simple assignment operator =, or otherwise one of the compound assignment operators (*= /= %= += -= <<= >>= &= ^= |=). The difference between initialization and assignment:

  • Initialization is when you give initial value(s) to an object at the point where the variable is defined, using an initializer list { ... }.
  • Assignment is when you give values to an object later on.

Initialization may happen at compile-time or during program launch, whereas assignment always happens in run-time. This difference matters in many scenarios, for example if we do this:

static int x = 1;
static int y = x;

Then the initialization of y is invalid since initialization of static storage duration objects must be done using constant expressions. However, would we just write y=x; later: then that is assignment, not initialization, and that's perfectly fine.

(The difference between initialization and assignment is even more important in C++ where you have constructors and overloaded assignment operators.)

Going back to the question, MY_TYPE a; ... a = { true, 15, 0.123 } is invalid C because a is first defined but not initialized. Then later an attempt to assign a value to a occurs, but that isn't even valid C syntax. This is because the { ... } is an initializer list, which may only be present during initialization, not during assignment.

This is particularly true for arrays where the C language simply does not allow assignment from arrays to arrays. As shown in some other answers, struct has a work-around for run-time assignment, namely by creating a temporary object known as a compound literal, which is written using the syntax
(type){initializer_list}.

MY_TYPE a;
a = (MY_TYPE){true, 15, 0.123};

Here (MY_TYPE){true, 15, 0.123} is a compound literal, an anonymous temporary object. That object is initialized using the provided initializer list. Then the temporary object is assigned to another struct object a of the same type, which is fine for structs specifically, but won't work for arrays.

The initialization rules of C
Whenever initializing an array or struct, this must be done using an initializer list with the curly braces {}, aka "brace-enclosed list".

The initializer rules work so that the compiler looks at the array or struct being initialized and starts with the first item. In case of arrays that is the object at index [0]. In case of structs it is the first member in the list: flag in the example struct from the question.

This first object is then set as the current object during initialization (C23 6.7.11). The compiler looks at the first item in the initializer list and then attempts to give that one to the current object. This is done as per "the rules of assignment" (C23 6.5.17), which I won't go into here, but come with a little bit of type safety. After that, the current object to be initialized becomes the next item in the array or the next member in the struct, which will get set to the next item present in the initializer list. The program will keep doing this until it runs out of objects to initialize in the array/struct.

  • If the amount of items in the array/struct matches the amount of items in the initializer list, then all is well.

  • If the amount of items in the array/struct are fewer than the amount of items in the initializer list, then that's invalid C.

    It is "a constraint violation". C23 6.7.11: "No initializer shall attempt to provide a value for an object not contained within the entity being initialized. The compiler will give a message about that, maybe something slightly cryptic like "excess elements in struct initializer".

  • If the amount of items in the array/struct are more than the amount of items in the initializer list, but there is at least one initializer present, then we have a partial initialization. In this case, the items that had no matching initializer are initialized to zero/NULL depending on their type.

    (Older C standards call this "initialization as if it had static storage duration", C23 calls it "default initialization" but it works the same.)

In practice, initialization might happen all at once, the mechanics with "the current object" is just the theory describing how the compiler should act when pairing together items in the array/struct with the initializer list.

Arrays/structs within arrays/structs
Looking into more advanced rules, we may have initializer lists within the initializer list - for initializing structs within structs etc. For example:

typedef struct {
  int x;
  int y;
} inner;

typedef struct MY_TYPE {
  inner in;
  bool flag;
  short int value;
  double stuff;
} MY_TYPE;

MY_TYPE a = { {1,2}, true, 15, 0.123 };

Here it will first set in as the current object, then (recursively) within that one pick the first item in.x as the current object. It is good practice to provide the inner brace-enclosed initializer list as above. But it is actually not mandatory! If we skip braces then the compiler will attempt to set the current object the best it can given the order of the items, so we could create an initializer list like this:

MY_TYPE a = { 1,2, true, 15, 0.123 };

This is bad practice and the compiler might warn, but it is valid C. The list is iterated through as before, by shifting current object and then picking the next item in the initializer list to initialize the object with - regardless if there are braces present or not.

This is convenient in one way, because we may write an initializer list like MY_TYPE a = {0};. What happens here is that the first struct member is initialized to zero. Then the initializer list ends - as we learned before this is a partial initialization and the remaining objects will then also get set to 0/NULL. And that's why we can initialize a whole array or struct to zero like this, regardless of any number of sub-objects present. But it won't work with MY_TYPE a = {1};, here the first object gets set to 1 and the rest to zero, not all of them to 1 as was perhaps the intention.

But obviously leaving out braces is also dangerous, if we forget one object or mix up initializers. In my example with the inner struct, suppose we forget to set the inner struct's member y in the initializer list:
MY_TYPE a = { 1, true, 15, 0.123 };. That will unfortunately compile, in.y will get initialized to true instead, then the rest of the items get the wrong initializer too, until the last item stuff which now suddenly isn't initialized explicitly, it gets set to zero since it becomes a partial initialization. Making slips and bugs like that is easy when the initializer lists are long and complex.

Initialization in modern C
With the C99 version of C, an alternative way of initialization was added for clarity. Instead of manually keeping track of which array/struct item that matches with which initializer in the initializer list, we can state it explicitly with a feature called designated initializers. For arrays it may look like this, with an inner [] naming the object index to initialize:

int arr[3] = { [0]=1, [1]=2, [2]=3 };

And for structs, it is done by writing a . dot, then the member's name:

MY_TYPE a = { .flag=true, .value=15, .stuff=0.123 };

This is much more explicit and clear, particularly when it comes to structs. Bugs related to miscounting the amount of members/initializers can be eliminated and we create a direct relation between the object to initialize and the initializer instead of relying on the old mechanism with implicit setting of next current object. It is really a great feature, to the point where using the older form without designated initializers for structs becomes questionable, since it has a much higher potential for accidental bugs.

Designated initializers do use the same initialization concept of setting the current object, but instead of automatically picking the next member in the struct as the current object, it jumps to the one we requested and then makes than the current object and initializes that one.

It is not entirely unproblematic though. We can combine designated initializers with the older form of letting the next current object determine initialization:

int arr[3] = { [1]=2, 3 };

Here, only items at index 1 and 2 are initialized explicitly. First we requested index 1 explicitly with a designed initializer, then the next current object is picked automatically as the next one after index 1, so index 2. Whereas index 0 was not initialized explicitly here - we get partial initialization and it gets initialized to zero.

Obviously this can become unreadable and dangerous, and with designated initializers we might even end up initializing an item twice. Best practice is therefore to always initialize all objects present, particularly whenever designated initializers are used.

Initialization in even more modern C (C23)
C23 did some mostly cosmetic changes to terminology with the introduction of default initialization, which happens to objects that were not initialized explicitly during partial initialization.

But C23 also allows an empty initializer MY_TYPE a = {}; which essentially works just like {0} did previously, with the slight cosmetic difference that instead of setting the first object to zero and the rest as if it had static storage duration, all objects are now initialized according to default initialization.

Before C23, some compilers like gcc supported non-standard extensions for an empty initializer lists.

Order of evaluation during initialization/assignment
Note that the order in which an array/struct is initialized is a separate matter from the order of evaluation of items in the initializer list. The items in the initializer list are "indeterminately sequenced" (C23 6.7.11). Meaning that in a case like int arr[] = { f1(), f2(), f3() };, we can't know the order in which the functions are executed - likely all of them are before initialization even begins, in an unspecified order. Similarly, something like int arr[] = {i, i++}; invokes undefined behavior.

Best practice here is to never put any expressions with side effects (assignments, ++ operators etc) inside an initializer list.

1 Comment

An additional detail is that designators may be chained together in a list to designate a nested element or member, but perhaps the answer is long enough already!
-4

I've been looking for a nice way to initialize my struct, and I've got to using the below (C99). This lets me initialize either a single structure or an array of structures in the same way as plain types.

typedef struct {
    char *str;
    size_t len;
    jsmntok_t *tok;
    int tsz;
} jsmn_ts;

#define jsmn_ts_default (jsmn_ts){NULL, 0, NULL, 0}

This can be used in the code as:

jsmn_ts mydata = jsmn_ts_default; /* initialization of a single struct */

jsmn_ts myarray[10] = {jsmn_ts_default, jsmn_ts_default}; /* initialization of
                                                    first 2 structs in the array */

2 Comments

But this does not initialize an array of structures to the default values. It initializes the first structure in the array to the values given in jsmn_ts_default, but the rest of the structures are initialized as if the array had static storage duration, which means that the members are initialized to NULL and 0. But if you change to #define jsmn_ts_default (jsmn_ts){"default", sizeof "default", NULL, 0} you will see that only the first array element gets so initialized.
Yes, I just came back from more testing, wanted to edit the post :) btw, same behaviour happens with int a[10] = {1}; Only the 1st element will be ==1

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.