ChatGPT解决这个技术问题 Extra ChatGPT

How to initialize a struct in accordance with C programming language standards

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.

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..
@KarolyHorvath well, most of the good answers are specific to C99. Maybe my question is a duplicate of stackoverflow.com/questions/6624975/… ?
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)
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.)
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.

N
Neuron

In (ANSI) 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)


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".
J
Jonathan Leffler

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 };

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
M
Mr. Polywhirl

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

Good luck!


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?
q
qrdl

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

would do fine in C99


N
Neuron

You've almost got it...

MY_TYPE a = { true, 15, 0.123 };

Quick search on 'struct initialize c' shows me this


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

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.


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."
N
Neuron

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.


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

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

designated-initializers-c | geeksforgeeks.org

using-designated-initializers

tutorialspoint.com | designated-initializers-in-c


d
dev

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;
}

N
Neuron

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.


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.
D
David Guyon
void function(void) {
  MY_TYPE a;
  a.flag = true;
  a.value = 15;
  a.stuff = 0.123;
}

once i've heard 'initialization is different than assignment'. so isn't this an assignment rather than initialization?
P
Palec

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.


N
Neuron

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


t
tdube

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;
}

H
Hartmut Schorrig

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

Use the = {0};-initialization for all static data. It is less effort for the machine code. 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);

d
div0man

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 */

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