471,108 Members | 1,571 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,108 software developers and data experts.

Surprising struct initialization

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?
Jul 3 '08 #1
10 4785
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
Jul 3 '08 #2
Juha Nieminen <no****@thanks.invalidkirjutas:
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

Jul 3 '08 #3
On Jul 3, 9:05*am, Juha Nieminen <nos...@thanks.invalidwrote:
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
Jul 3 '08 #4
On Jul 3, 6:05 pm, Juha Nieminen <nos...@thanks.invalidwrote:
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:ja*********@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
Jul 4 '08 #5
On Jul 3, 9:57 pm, Paavo Helde <nob...@ebi.eewrote:
Juha Nieminen <nos...@thanks.invalidkirjutas:
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:ja*********@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
Jul 4 '08 #6
On Jul 4, 8:16 pm, James Kanze <james.ka...@gmail.comwrote:
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 };
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.

Jul 4 '08 #7
Old Wolf wrote:
On Jul 4, 8:16 pm, James Kanze <james.ka...@gmail.comwrote:
>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 };
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?)
Jul 4 '08 #8
On Jul 5, 4:00 am, Juha Nieminen <nos...@thanks.invalidwrote:
Old Wolf wrote:
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.
Jul 5 '08 #9
On Jul 4, 6:54 pm, Old Wolf <oldw...@inspire.net.nzwrote:
On Jul 5, 4:00 am, Juha Nieminen <nos...@thanks.invalidwrote:
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

Jul 5 '08 #10
On Jul 5, 5:27 am, Greg Herlihy <gre...@mac.comwrote:
On Jul 4, 6:54 pm, Old Wolf <oldw...@inspire.net.nzwrote:
On Jul 5, 4:00 am, Juha Nieminen <nos...@thanks.invalidwrote:
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:ja*********@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
Jul 5 '08 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

5 posts views Thread by John Smith | last post: by
4 posts views Thread by Everton | last post: by
3 posts views Thread by jilerner | last post: by
21 posts views Thread by Zytan | last post: by
6 posts views Thread by Daniel Rudy | last post: by
2 posts views Thread by dj3vande | last post: by
2 posts views Thread by quadraticformula | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.