views:

1428

answers:

5

I found some struct initialization code yesterday that threw me for a loop. Here's an example:

typedef struct { int first; int second; } TEST_STRUCT;
void testFunc() {
    TEST_STRUCT test = {
     second: 2,
     first: 1
    };
    printf("test.first=%d test.second=%d\n", test.first, test.second);
}

Surprisingly (to me), here's the output:

-> testFunc
test.first=1 test.second=2

As you can see, the struct gets initialized properly. I wasn't aware labeled statements could be used like that. I've seen several other ways of doing struct initialization, but I didn't find any examples of this sort of struct initialization on any of the online C FAQs. Is anybody aware of how/why this works? Or documentation stating it is correct syntax?

+2  A: 

It's not really "labeled statements", but a way to give initial values to the named fields in the struct.

Gcc gives a warning about "obsolete use of designated initializer with ':'", and in C99 you should instead write:

    TEST_STRUCT test = {
        .second = 2,
        .first =  1
    };
Thomas Padron-McCarthy
+9  A: 

These are neither labels nor bitfields.

This is a syntax to initialize struct members dating back to the days before C99. It is not standardized but available in e.g. gcc.

typedef struct { int y; int x; } POINT;
POINT p = { x: 1, y: 17 };

In C99, syntax for initializting specific struct members has been introduced for the first time in a standard, but it looks a little differently:

typedef struct { int y; int x; } POINT;
POINT p = { .x = 1, .y = 17 };
ndim
Yep, I was aware of the designated initializer format. Unfortunately that format isn't compatible with C++! (Not in my testing anyway.) Thanks for the answer though. Good to know this is not standardized.
Andrew Cottrell
@Andrew you never said anything about C++ in your question
banister
+1  A: 

That syntax is not defined by the C Standard. Section 6.7.8 Initialization says

         designation:
                designator-list =
         designator-list:
                designator
                designator-list designator
         designator:
                [ constant-expression ]
                . identifier

If your compiler accepts a designation with a colon without a diagnostic message it means your compiler is not (or is configured not to be) Standards compliant.

pmg
+2  A: 

Here is the section of the gcc manual which explains the syntax of designated initializers for both structs and arrays. Your compiler should have similar documentation.

sigjuice
Excellent, that documentation clearly explains the syntax:Another syntax which has the same meaning, obsolete since GCC 2.5, is `fieldname:', as shown here: struct point p = { y: yvalue, x: xvalue };
Andrew Cottrell
A: 

Yes, as pointed out above, these are designated initializers, which are standard C, though you should switch to using periods instead of colons. And as you note, most of the books out there are still stuck somewhere around 1984 in their syntax and fail to mention them. More fun facts:

--When using designated initializers, everything not specified is initialized at zero. This helps with exceptionally large structs, e.g.:

typedef struct {
   double a, b, c, d, e;
   char label[100];
} too_many_type;

too_many_type tm = {.a = 1, .e = 2, .b=1.5};
assert(tm.a + tm.b + tm.c + tm.d + tm.e == 4.5);
assert(!strlen(label));

--Also, you can use the compound literal form to use this form on a non-initialization line, e.g.:

too_many_type tm2;
tm2 = (too_many_type) {.a = 3, .e=6};

These are really great features, and are supported by every C compiler that I can think of, being that it's the standard. It's a shame that they're not so well known.

bk