Login or Sign up Help | Site Map
Connecting Tech Pros Worldwide

Surprising struct initialization

Question posted by: Juha Nieminen (Guest) on July 3rd, 2008 04:15 PM
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?
Would you like to answer this question?
Sign up for a free account, or Login (if you're already a member).
phlip's Avatar
phlip
Guest
n/a Posts
July 3rd, 2008
04:15 PM
#2

Re: Surprising struct initialization
Juha Nieminen wrote:
Quote:
Originally Posted by
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

Paavo Helde's Avatar
Paavo Helde
Guest
n/a Posts
July 3rd, 2008
08:05 PM
#3

Re: Surprising struct initialization
Juha Nieminen <nospam@thanks.invalidkirjutas:
Quote:
Originally Posted by
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.

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

Paavo


Greg Herlihy's Avatar
Greg Herlihy
Guest
n/a Posts
July 3rd, 2008
08:05 PM
#4

Re: Surprising struct initialization
On Jul 3, 9:05*am, Juha Nieminen <nos...@thanks.invalidwrote:
Quote:
Originally Posted by
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



James Kanze's Avatar
James Kanze
Guest
n/a Posts
July 4th, 2008
08:25 AM
#5

Re: Surprising struct initialization
On Jul 3, 6:05 pm, Juha Nieminen <nos...@thanks.invalidwrote:
Quote:
Originally Posted by
I suppose you can never know C++ fully. I would have never
guessed this actually compiles and works:

Quote:
Originally Posted by
struct Point { int x, y; };

Quote:
Originally Posted by
struct Line
{
Point endpoint[2];
int weight;
};

Quote:
Originally Posted by
Line createLine(int sx, int sy, int ex, int ey)
{
Line l = { sx, sy, ex, ey, 1 };
return l;
}


Why shouldn't it?
Quote:
Originally Posted by
Both gcc and Visual Studio 2005 compile that happily.

Quote:
Originally Posted by
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:james.kanze@gmail.com
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's Avatar
James Kanze
Guest
n/a Posts
July 4th, 2008
08:35 AM
#6

Re: Surprising struct initialization
On Jul 3, 9:57 pm, Paavo Helde <nob...@ebi.eewrote:
Quote:
Originally Posted by
Juha Nieminen <nos...@thanks.invalidkirjutas:

Quote:
Originally Posted by
Quote:
Originally Posted by
I suppose you can never know C++ fully. I would have never
guessed this actually compiles and works:

Quote:
Originally Posted by
Quote:
Originally Posted by
struct Point { int x, y; };

Quote:
Originally Posted by
Quote:
Originally Posted by
struct Line
{
Point endpoint[2];
int weight;
};

Quote:
Originally Posted by
Quote:
Originally Posted by
Line createLine(int sx, int sy, int ex, int ey)
{
Line l = { sx, sy, ex, ey, 1 };
return l;
}

Quote:
Originally Posted by
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.)
Quote:
Originally Posted by
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:james.kanze@gmail.com
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

Old Wolf's Avatar
Old Wolf
Guest
n/a Posts
July 4th, 2008
03:45 PM
#7

Re: Surprising struct initialization
On Jul 4, 8:16 pm, James Kanze <james.ka...@gmail.comwrote:
Quote:
Originally Posted by
On Jul 3, 6:05 pm, Juha Nieminen <nos...@thanks.invalidwrote:
Quote:
Originally Posted by
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.


Juha Nieminen's Avatar
Juha Nieminen
Guest
n/a Posts
July 4th, 2008
04:05 PM
#8

Re: Surprising struct initialization
Old Wolf wrote:
Quote:
Originally Posted by
On Jul 4, 8:16 pm, James Kanze <james.ka...@gmail.comwrote:
Quote:
Originally Posted by
>On Jul 3, 6:05 pm, Juha Nieminen <nos...@thanks.invalidwrote:
Quote:
Originally Posted by
>>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?)

Old Wolf's Avatar
Old Wolf
Guest
n/a Posts
July 5th, 2008
01:55 AM
#9

Re: Surprising struct initialization
On Jul 5, 4:00 am, Juha Nieminen <nos...@thanks.invalidwrote:
Quote:
Originally Posted by
Old Wolf wrote:
Quote:
Originally Posted by
Quote:
Originally Posted by
On Jul 3, 6:05 pm, Juha Nieminen <nos...@thanks.invalidwrote:
>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.

Greg Herlihy's Avatar
Greg Herlihy
Guest
n/a Posts
July 5th, 2008
03:35 AM
#10

Re: Surprising struct initialization
On Jul 4, 6:54 pm, Old Wolf <oldw...@inspire.net.nzwrote:
Quote:
Originally Posted by
On Jul 5, 4:00 am, Juha Nieminen <nos...@thanks.invalidwrote:
Quote:
Originally Posted by
Old Wolf wrote:
Quote:
Originally Posted by
>>{
>> Line l = { sx, sy, ex, ey, 1 };
A minor point; the above initialization is
illegal in C90 which requires initializers
to be constant expressions.

>
Quote:
Originally Posted by
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


James Kanze's Avatar
James Kanze
Guest
n/a Posts
July 5th, 2008
08:05 AM
#11

Re: Surprising struct initialization
On Jul 5, 5:27 am, Greg Herlihy <gre...@mac.comwrote:
Quote:
Originally Posted by
On Jul 4, 6:54 pm, Old Wolf <oldw...@inspire.net.nzwrote:

Quote:
Originally Posted by
Quote:
Originally Posted by
On Jul 5, 4:00 am, Juha Nieminen <nos...@thanks.invalidwrote:
Quote:
Originally Posted by
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.

Quote:
Originally Posted by
Quote:
Originally Posted by
Quote:
Originally Posted by
I thought that was only the case with array
initialization. (Or is it the other way around nowadays?)

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

Quote:
Originally Posted by
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:james.kanze@gmail.com
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

 
Not the answer you were looking for? Post your question . . .
183,962 Experts ready to help you find a solution.
Sign up for a free account, or Login (if you're already a member).

Latest Articles: Read & Comment
  • Didn't find the answer you were looking for?
    Post Your Question
  • Top Community Contributors