Surprising struct initialization

Discussion in 'C++' started by Juha Nieminen, Jul 3, 2008.

  1. I suppose you can never know C++ fully. I would have never guessed
    this actually compiles and works:

    struct Point { int x, y; };

    struct Line
    {
    Point endpoint[2];
    int weight;
    };

    Line createLine(int sx, int sy, int ex, int ey)
    {
    Line l = { sx, sy, ex, ey, 1 };
    return l;
    }

    Both gcc and Visual Studio 2005 compile that happily.

    My question would be: Is that *really* correct, or are both compilers
    simply being lenient? What are the exact rules for the initialization
    blocks of structs?
     
    Juha Nieminen, Jul 3, 2008
    #1
    1. Advertising

  2. Juha Nieminen

    phlip Guest

    Juha Nieminen wrote:

    > I suppose you can never know C++ fully. I would have never guessed
    > this actually compiles and works:
    >
    > struct Point { int x, y; };
    >
    > struct Line
    > {
    > Point endpoint[2];
    > int weight;
    > };
    >
    > Line createLine(int sx, int sy, int ex, int ey)
    > {
    > Line l = { sx, sy, ex, ey, 1 };
    > return l;
    > }
    >
    > Both gcc and Visual Studio 2005 compile that happily.
    >
    > My question would be: Is that *really* correct, or are both compilers
    > simply being lenient? What are the exact rules for the initialization
    > blocks of structs?


    IIRC, if a struct (or an abused class) is a POD, you can aggregate its
    construction using classic C notation. POD is Plain Ole' Data - no virtuals,
    constants, etc. A POD has an implementation-defined memory layout - and strict
    top-to-bottom member locations - so the {,,,} can exploit this to unambiguously
    drop data into each slot.

    --
    Phlip
     
    phlip, Jul 3, 2008
    #2
    1. Advertising

  3. Juha Nieminen

    Greg Herlihy Guest

    On Jul 3, 9:05 am, Juha Nieminen <> wrote:
    > struct Point { int x, y; };
    >
    > struct Line
    > {
    >     Point endpoint[2];
    >     int weight;
    > };
    >
    > Line createLine(int sx, int sy, int ex, int ey)
    > {
    >     Line l = { sx, sy, ex, ey, 1 };
    >     return l;
    > }
    >
    >   Both gcc and Visual Studio 2005 compile that happily.
    >
    >   My question would be: Is that *really* correct, or are both compilers
    > simply being lenient? What are the exact rules for the initialization
    > blocks of structs?


    The compilers are not being lenient - multiple braces can be elided in
    an aggregate initializer. Therefore, a program can replace this:

    Line l = {{{sx, sy}, {ex, ey}}, 1 };

    with:

    Line l = {sx, sy, ex, ey, 1 };

    as long as there are enough arguments to match the aggregate members.
    Otherwise, the braces would be needed. For example:

    Line l = {{{sx, xy}}, 1}; // l.endpoint[1] is initialized to {0,
    0}

    I would leave the braces in an aggregate initializer (even when not
    needed) just to make the code more readable.

    Greg
     
    Greg Herlihy, Jul 3, 2008
    #3
  4. Juha Nieminen

    James Kanze Guest

    On Jul 3, 6:05 pm, Juha Nieminen <> wrote:
    > I suppose you can never know C++ fully. I would have never
    > guessed this actually compiles and works:


    > struct Point { int x, y; };


    > struct Line
    > {
    > Point endpoint[2];
    > int weight;
    > };


    > Line createLine(int sx, int sy, int ex, int ey)
    > {
    > Line l = { sx, sy, ex, ey, 1 };
    > return l;
    > }


    Why shouldn't it?

    > Both gcc and Visual Studio 2005 compile that happily.


    > My question would be: Is that *really* correct, or are both
    > compilers simply being lenient? What are the exact rules for
    > the initialization blocks of structs?


    The same as in C, at least in the case of POD agglomerates. In
    the places I've worked, it's generally considered good practice
    to put in all of the braces, e.g.:

    Line l = { { { sx, sy }, { ex, ey } }, 1 } ;

    but the language allows many or all of them to be elided. (The
    exact rules are fairly complex, and in a code review, I would
    reject any code that elided some without eliding all. But
    initializers like the one you present were common in C, and so
    are legal in C++ as well.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 4, 2008
    #4
  5. Juha Nieminen

    James Kanze Guest

    On Jul 3, 9:57 pm, Paavo Helde <> wrote:
    > Juha Nieminen <> kirjutas:


    > > I suppose you can never know C++ fully. I would have never
    > > guessed this actually compiles and works:


    > > struct Point { int x, y; };


    > > struct Line
    > > {
    > > Point endpoint[2];
    > > int weight;
    > > };


    > > Line createLine(int sx, int sy, int ex, int ey)
    > > {
    > > Line l = { sx, sy, ex, ey, 1 };
    > > return l;
    > > }


    > This is using the C subset of C++, for both data objects and
    > initialization, and is perfectly fine as it is. But just add a
    > ctor to Point or Line to make them non-POD and the
    > initialization would be illegal.


    The exact form he has written would become illegal, but
    aggregate initialization is legal for any aggregate, and there's
    no problem with something like:

    class Point
    {
    int x ;
    int y ;
    public:
    Point( int a, int b ) ;
    // other functions as well...
    } ;

    struct Line
    {
    Point endpoint[ 2 ] ;
    int weight ;
    } ;

    Line createLine(int sx, int sy, int ex, int ey)
    {
    Line l = { Point( sx, sy ), Point( ex, ey ), 1 };
    return l;
    }

    (IIRC, some older versions of VC++ didn't accept this. But that
    was a bug in the compiler---it's always been perfectly legal.)

    > AFAIK the next C++ standard will relax some constraints for
    > PODness and add some syntax for convenient initialization of
    > genuine C++ classes as well.


    There are several important evolutions concerning
    initialization, although I'm not too sure about the details. I
    do know, however, that one of the goals was to reduce the
    differences in the initialization syntax according to whether
    the class was an agglomerate or not.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 4, 2008
    #5
  6. Juha Nieminen

    Old Wolf Guest

    On Jul 4, 8:16 pm, James Kanze <> wrote:
    > On Jul 3, 6:05 pm, Juha Nieminen <> wrote:
    > > Line createLine(int sx, int sy, int ex, int ey)
    > > {
    > > Line l = { sx, sy, ex, ey, 1 };
    > > return l;
    > > }

    > initializers like the one you present were common in C, and so
    > are legal in C++ as well.)


    A minor point; the above initialization is
    illegal in C90 which requires initializers
    to be constant expressions.
     
    Old Wolf, Jul 4, 2008
    #6
  7. Old Wolf wrote:
    > On Jul 4, 8:16 pm, James Kanze <> wrote:
    >> On Jul 3, 6:05 pm, Juha Nieminen <> wrote:
    >>> Line createLine(int sx, int sy, int ex, int ey)
    >>> {
    >>> Line l = { sx, sy, ex, ey, 1 };
    >>> return l;
    >>> }

    >> initializers like the one you present were common in C, and so
    >> are legal in C++ as well.)

    >
    > A minor point; the above initialization is
    > illegal in C90 which requires initializers
    > to be constant expressions.


    I thought that was only the case with array initialization. (Or is it
    the other way around nowadays?)
     
    Juha Nieminen, Jul 4, 2008
    #7
  8. Juha Nieminen

    Old Wolf Guest

    On Jul 5, 4:00 am, Juha Nieminen <> wrote:
    > Old Wolf wrote:
    > >> On Jul 3, 6:05 pm, Juha Nieminen <> wrote:
    > >>> Line createLine(int sx, int sy, int ex, int ey)
    > >>> {
    > >>> Line l = { sx, sy, ex, ey, 1 };

    > > A minor point; the above initialization is
    > > illegal in C90 which requires initializers
    > > to be constant expressions.

    >
    > I thought that was only the case with array initialization. (Or is it
    > the other way around nowadays?)


    Nowadays (C99) the above is allowed. But in C90
    brace-enclosed initializers (for structs and
    arrays) had to be constant expressions.
     
    Old Wolf, Jul 5, 2008
    #8
  9. Juha Nieminen

    Greg Herlihy Guest

    On Jul 4, 6:54 pm, Old Wolf <> wrote:
    > On Jul 5, 4:00 am, Juha Nieminen <> wrote:
    > > Old Wolf wrote:
    > > >>> {
    > > >>> Line l = { sx, sy, ex, ey, 1 };
    > > > A minor point; the above initialization is
    > > > illegal in C90 which requires initializers
    > > > to be constant expressions.

    >
    > > I thought that was only the case with array initialization. (Or is it
    > > the other way around nowadays?)

    >
    > Nowadays (C99) the above is allowed. But in C90
    > brace-enclosed initializers (for structs and
    > arrays) had to be constant expressions.


    No, C99 has the same, const-expression initializer requirements for
    arrays - as C90 did: namely, that the initializers for arrays with
    static storage duration must be constant expressions, whereas the
    initializers for arrays with other-than-static storage duration have
    no such requirement

    So the initializer of "l" array above would be legal (in both C90 and
    C99) - just as long as the "l" array is a local variable.

    Greg
     
    Greg Herlihy, Jul 5, 2008
    #9
  10. Juha Nieminen

    James Kanze Guest

    On Jul 5, 5:27 am, Greg Herlihy <> wrote:
    > On Jul 4, 6:54 pm, Old Wolf <> wrote:


    > > On Jul 5, 4:00 am, Juha Nieminen <> wrote:
    > > > Old Wolf wrote:
    > > > >>> {
    > > > >>> Line l = { sx, sy, ex, ey, 1 };
    > > > > A minor point; the above initialization is
    > > > > illegal in C90 which requires initializers
    > > > > to be constant expressions.


    > > > I thought that was only the case with array
    > > > initialization. (Or is it the other way around nowadays?)


    > > Nowadays (C99) the above is allowed. But in C90
    > > brace-enclosed initializers (for structs and
    > > arrays) had to be constant expressions.


    > No, C99 has the same, const-expression initializer
    > requirements for arrays - as C90 did: namely, that the
    > initializers for arrays with static storage duration must be
    > constant expressions, whereas the initializers for arrays with
    > other-than-static storage duration have no such requirement


    That's what I always thougt too, but on pulling out my old
    copy of C90, I find (§6.5.7, in the Constraints section):

    All of the expressions in an initializer for an object
    that has static storage duration or in an initializer
    list for an object that has aggregate or union type
    shall be constant expressions.

    And in §6.1.2.5, "Array and structure types are collectively
    called aggregate types" (with "aggregate types" in italics,
    so this is a definition).

    Historically, of course, K&R C required constant expressions
    for all aggregate initialization, and C99 only requires them
    for variables with static lifetime. Apparently, the change
    didn't take place until after C90 (although I remember it as
    being before).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 5, 2008
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. naija naija

    Help with Datagrid (Surprising No Data!!)

    naija naija, Sep 30, 2004, in forum: ASP .Net
    Replies:
    2
    Views:
    425
    naijacoder naijacoder
    Oct 2, 2004
  2. janek
    Replies:
    3
    Views:
    413
    Ioannis Vranos
    Feb 21, 2005
  3. Michael Olea

    A Surprising Partial Specialization

    Michael Olea, Jun 14, 2005, in forum: C++
    Replies:
    1
    Views:
    313
    Pete Becker
    Jun 14, 2005
  4. Chris Fogelklou
    Replies:
    36
    Views:
    1,391
    Chris Fogelklou
    Apr 20, 2004
  5. Replies:
    2
    Views:
    740
    David Harmon
    Sep 20, 2006
Loading...

Share This Page