473,889 Members | 2,193 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

union initializers idiosyncrasies


Hello,

I would like to know what the C standards (and in particular the C99
standard) have to say about union initializers with regards to the
following code snippet (which compiles fine under gcc 3.2.2 but
does not produce the expected results, the expected results
being the ones annotated in the comments in the code):

#include <stdlib.h>

union Foo {
struct {
int y1;
union {
int z1;
float z2;
} y2;
} x;
void *a;
};

int main(void) {
union Foo foobar1 = { { 1, { 22 } } };
union Foo foobar2 = { { 2, { 33.1 } } };
/* expecting 1, OK */
printf("foobar1 : %d\n", foobar1.x.y1);
/* expecting 22, OK */
printf("foobar1 : %d\n", foobar1.x.y2.z1 );
/* expecting 2, OK */
printf("foobar2 : %d\n", foobar2.x.y1);
/* expecting 33.1, not 0.00 */
printf("foobar2 : %f\n", foobar2.x.y2.z2 );
}

I would have thought, that seeing that 33.1 is a float and not an
integer, the float would have been properly stored in the union.
What does the standard say about the above code; is any of it
illegal or is any of it subject to implementation dependent
behavior, and if so then why didn't gcc complain?

Thank you for your clarifications,

Neil

Nov 13 '05 #1
6 3339
On Tue, 16 Sep 2003 23:33:50 -0230, Neil Zanella <nz******@cs.mu n.ca>
wrote in comp.lang.c:

Hello,

I would like to know what the C standards (and in particular the C99
standard) have to say about union initializers with regards to the
following code snippet (which compiles fine under gcc 3.2.2 but
does not produce the expected results, the expected results
being the ones annotated in the comments in the code):

#include <stdlib.h>

union Foo {
struct {
int y1;
union {
int z1;
float z2;
} y2;
} x;
void *a;
};

int main(void) {
union Foo foobar1 = { { 1, { 22 } } };
union Foo foobar2 = { { 2, { 33.1 } } };
/* expecting 1, OK */
printf("foobar1 : %d\n", foobar1.x.y1);
/* expecting 22, OK */
printf("foobar1 : %d\n", foobar1.x.y2.z1 );
/* expecting 2, OK */
printf("foobar2 : %d\n", foobar2.x.y1);
/* expecting 33.1, not 0.00 */
printf("foobar2 : %f\n", foobar2.x.y2.z2 );
}

I would have thought, that seeing that 33.1 is a float and not an
integer, the float would have been properly stored in the union.
What does the standard say about the above code; is any of it
illegal or is any of it subject to implementation dependent
behavior, and if so then why didn't gcc complain?

Thank you for your clarifications,

Neil


The nesting of unions has nothing at all to do with this, the results
would be the same if y2 were defined as a separate union.

You thought incorrectly. Prior to C99, and even under C99 using the
syntax you are using, it is only possible to initialize the first
member of a union, in definition order. The type of the initializer
is irrelevant as long as it is assignment compatible with the
destination type.

Consider this:

union x
{
int i; long l; float f; double d; long double ld;
};

union x q = { 1 }; /* initialize the int or the long? */
union x r = { 1.0 }; /* float, double, or long double? */

Why should you expect an error for the second initialization? There
is nothing illegal about this:

int i = 3.14159;

....although as a QOI issue you might like to see a warning from the
compiler. If it actually refused to compile it, the compiler would be
broken.

The only time such code is illegal is if the initializer is not
assignment compatible (without a cast) with the type being
initialized:

char *cp = 3.14159;

....requires a diagnostic.

C99 has added designated initializers which allow you to initialize
any specific member of a union, but the syntax is quite different.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
Nov 13 '05 #2
Hello,

Thank you for your detailed reply...

Jack Klein <ja*******@spam cop.net> wrote in message:
You thought incorrectly. Prior to C99, and even under C99 using the
syntax you are using, it is only possible to initialize the first
member of a union, in definition order. The type of the initializer
is irrelevant as long as it is assignment compatible with the
destination type.
The C99 standard discusses the above matter in Section 6.7.8.
Furthermore,
page 347 of K.N.King's C book which covers C95 states the following
about
unions:

--- begin quote ---
Like structures, unions can be copied using the = operator, passed to
functions, and returned to functions.
--- end quote ---

This covers the legality of using assignment to copy unions. Then it
states:

--- begin quote ---
Unions can even be initialized in a manner similar to structures.
However,
only the first member of a union can be given an initial value.
--- end quote ---

This is not true in C99 (see below). Even though only one member of a
union
can be initialized in C99 (which makes sense since all union members
share
the same storage space), we can now initialize any member of the
union, not
only the one that appears first in the union declaration. We do this
by
specifying the member name explicitly inside the union initializer
list.
From the C99 standard:
C99 has added designated initializers which allow you to initialize
any specific member of a union, but the syntax is quite different.


Yes, from the C99 standard we can see the following example which
shows
us how this can be achieved:

Section 6.7.8, paragraph 130, EXAMPLE 13

--- begin quote ---
union { /* ... */ } u = { .any_member = 42 };
--- end quote ---

This C99 idiom lends itself to good programming style. As long as we
use
member names in union initializer lists we can reorder the members of
unions in the union definition.

-------------------------------------------------------------------------

What the book does not cover is the following:

suppose I have something like:

int main(void) {
union foo { int c; double d; } x;
/* ... */
x.d = 3.3;
/* ... */
union foo y = x;
/* let's check that it worked */
printf("%g\n", x.d);
/* it works with my compiler, outputs 3.3 with gcc 3.2.2 */
return 0;
}
Here I am initializing union y with an expression, x, which is a
union.
Here it is true that d is not the first member of x. Nevertheless, is
it
true in this case that y.d == 3.3 after y gets declared as above? The
C99 standard states the following:

Section 6.7.8, paragraph 13, page 126

--- begin quote ---
The initializer for a structure or union object that has automatic
storage duration shall be either an initializer list or a single
expression that has compatible structure or union type. In the
latter case, the initial value of the object, including unnamed
members, is that of the expression.
--- end quote ---

So what is the value of the expression x in the above example? I guess
the initial value of the object, that of the expression, is the union
itself in the above code, and that the above code is legal in C99.

Thanks you for your feedback and contributions,

Neil
Nov 13 '05 #3
Hello,

Here is a very simple way to fix the problem in C99:
#include <stdlib.h>

union Foo {
struct {
int y1;
union {
int z1;
float z2;
} y2;
} x;
void *a;
};

int main(void) {
union Foo foobar1 = { { 1, { 22 } } };
/* union Foo foobar2 = { { 2, { 33.1 } } }; */
union Foo foobar2 = { { 2, { .z2 = 33.1 } } };
/* expecting 1, OK */
printf("foobar1 : %d\n", foobar1.x.y1);
/* expecting 22, OK */
printf("foobar1 : %d\n", foobar1.x.y2.z1 );
/* expecting 2, OK */
printf("foobar2 : %d\n", foobar2.x.y1);
/* expecting 33.1, not 0.00 */
printf("foobar2 : %f\n", foobar2.x.y2.z2 );
/* output: 33.099998: OK (with usual but unrelated roundoff error) */
}


From the C99 standard:

--- begin quote ---
Forward, paragraph 5, page xiii
- relaxed constraints on aggregate and union initializations
--- end quote ---

I guess this is what this remark refers to.

Regards,

Neil
Nov 13 '05 #4
On 17 Sep 2003 18:19:31 -0700, nz******@cs.mun .ca (Neil Zanella) wrote
in comp.lang.c:
Hello,

Thank you for your detailed reply...

Jack Klein <ja*******@spam cop.net> wrote in message:
You thought incorrectly. Prior to C99, and even under C99 using the
syntax you are using, it is only possible to initialize the first
member of a union, in definition order. The type of the initializer
is irrelevant as long as it is assignment compatible with the
destination type.
The C99 standard discusses the above matter in Section 6.7.8.
Furthermore,
page 347 of K.N.King's C book which covers C95 states the following
about
unions:

--- begin quote ---
Like structures, unions can be copied using the = operator, passed to
functions, and returned to functions.
--- end quote ---

This covers the legality of using assignment to copy unions. Then it
states:

--- begin quote ---
Unions can even be initialized in a manner similar to structures.
However,
only the first member of a union can be given an initial value.
--- end quote ---

This is not true in C99 (see below). Even though only one member of a
union
can be initialized in C99 (which makes sense since all union members
share
the same storage space), we can now initialize any member of the
union, not
only the one that appears first in the union declaration. We do this
by
specifying the member name explicitly inside the union initializer
list.
From the C99 standard:
C99 has added designated initializers which allow you to initialize
any specific member of a union, but the syntax is quite different.


Yes, from the C99 standard we can see the following example which
shows
us how this can be achieved:

Section 6.7.8, paragraph 130, EXAMPLE 13

--- begin quote ---
union { /* ... */ } u = { .any_member = 42 };
--- end quote ---

This C99 idiom lends itself to good programming style. As long as we
use
member names in union initializer lists we can reorder the members of
unions in the union definition.

-------------------------------------------------------------------------

What the book does not cover is the following:

suppose I have something like:

int main(void) {
union foo { int c; double d; } x;
/* ... */
x.d = 3.3;
/* ... */
union foo y = x;
/* let's check that it worked */
printf("%g\n", x.d);
/* it works with my compiler, outputs 3.3 with gcc 3.2.2 */
return 0;
}
Here I am initializing union y with an expression, x, which is a
union.
Here it is true that d is not the first member of x. Nevertheless, is
it
true in this case that y.d == 3.3 after y gets declared as above? The
C99 standard states the following:

Section 6.7.8, paragraph 13, page 126

--- begin quote ---
The initializer for a structure or union object that has automatic
storage duration shall be either an initializer list or a single
expression that has compatible structure or union type. In the
latter case, the initial value of the object, including unnamed
members, is that of the expression.
--- end quote ---


You are still way over-thinking this, for some reason. You can
initialize any modifiable lvalue object in C with the value of another
object of compatible type. This has been true since the 1989 ANSI
standard. That is so basic that it is pretty much taken for granted.

When you write:

union some_type foo = { /* some valid initializer */ };
union some_type bar = foo;

....bar winds up being an exact member-wise copy of foo. In a
structure that would mean that each member in the new structure would
have the same value as the corresponding members of the initiating
structure. For a union it means that the new union will be in the
same "state" (my term, not the standard's) as the original one, namely
the one valid member in the union will be the last stored member in
the old union, and it will contain the same value.
So what is the value of the expression x in the above example? I guess
the initial value of the object, that of the expression, is the union
itself in the above code, and that the above code is legal in C99.
The above code was legal in C89, and was a common extension at the
time of publication of the first edition of K&R, in 1978. There is
nothing new to C99 about it.

There are differences between initialization and assignment, but they
are not important here. The two lines I wrote above are not the same
as the following three lines, but the result is the same:

union some_type foo = { /* some valid initializer */ };
union some_type bar;
bar = foo;
Thanks you for your feedback and contributions,

Neil


--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
Nov 13 '05 #5
Thanks Jack,

Your lucid explanation explains very well the semantic issues I brought
up on this newsgroup pertaining to union initialization and assignment.
Please don't take things personally. Basically I was looking for
something in the standard stating what you wrote here:

--- begin Jack's quote ---
For a union it means that the new union will be in the same "state"
(my term, not the standard's) as the original one, namely the one
valid member in the union will be the last stored member in
the old union, and it will contain the same value.
--- end Jack's quote ---

That's what I expected, even though in pre-C99 initializer lists it
is the first element in the union's definition that gets assigned,
which is what made me wonder about other kind of initializations .
Basically what I was trying to get at is that the standard should
perhaps have included something explicit to reflect what you
describe in the above quote, which is what we'd all expect.
C can be quirky, and unless the standard documents it, you
never know whether what you're doing is portable.

Thank you and have a nice day!

Neil

Jack Klein <ja*******@spam cop.net> wrote in message news:<3e******* *************** **********@4ax. com>...
You are still way over-thinking this, for some reason. You can
initialize any modifiable lvalue object in C with the value of another
object of compatible type. This has been true since the 1989 ANSI
standard. That is so basic that it is pretty much taken for granted.

When you write:

union some_type foo = { /* some valid initializer */ };
union some_type bar = foo;

...bar winds up being an exact member-wise copy of foo. In a
structure that would mean that each member in the new structure would
have the same value as the corresponding members of the initiating
structure. For a union it means that the new union will be in the
same "state" (my term, not the standard's) as the original one, namely
the one valid member in the union will be the last stored member in
the old union, and it will contain the same value.
So what is the value of the expression x in the above example? I guess
the initial value of the object, that of the expression, is the union
itself in the above code, and that the above code is legal in C99.


The above code was legal in C89, and was a common extension at the
time of publication of the first edition of K&R, in 1978. There is
nothing new to C99 about it.

There are differences between initialization and assignment, but they
are not important here. The two lines I wrote above are not the same
as the following three lines, but the result is the same:

union some_type foo = { /* some valid initializer */ };
union some_type bar;
bar = foo;
Thanks you for your feedback and contributions,

Neil

Nov 13 '05 #6
On 17 Sep 2003 18:25:54 -0700, nz******@cs.mun .ca (Neil Zanella)
wrote:
<snip>
union Foo foobar2 = { { 2, { .z2 = 33.1 } } }; <snip> From the C99 standard:

--- begin quote ---
Forward, paragraph 5, page xiii
- relaxed constraints on aggregate and union initializations
--- end quote ---

I guess this is what this remark refers to.

No, that item refers to 6.7.8p3, which in C90 also applied to "an
initializer list for an object that has aggregate or union type" even
if automatic; pre-Standard such automatic variables might not even be
initializable at all -- FAQ 1.31.

The item "ó designated initializers" on pxii refers to what you did.
Hint: 6.7.8, which is entirely about "initialization " and
"initialize r"s, consistently uses "designatio n" and "designated " for
this new feature.

- David.Thompson1 at worldnet.att.ne t
Nov 13 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
8164
by: Simon Elliott | last post by:
I'd like to do something along these lines: struct foo { int i1_; int i2_; }; struct bar {
73
4082
by: Sean Dolan | last post by:
typedef struct ntt { int type; union { int i; char* s; }; }nt; nt n; n.i = 0;
4
1723
by: John Devereux | last post by:
Hi, gcc has started warning about the lack of inner braces in initializers like :- struct io_descriptor { int number; char* description;
4
2597
by: Michael Brennan | last post by:
I have a menu_item structure containing an union. func is used if the menu item should use a callback, and submenu if a popupmen should be shown. struct menu_item { enum { function, popup } type; union { int (*func)(int); struct menu_item *submenu; } action;
30
3306
by: Yevgen Muntyan | last post by:
Hey, Why is it legal to do union U {unsigned char u; int a;}; union U u; u.a = 1; u.u; I tried to find it in the standard, but I only found that
5
3855
by: wugon.net | last post by:
question: db2 LUW V8 UNION ALL with table function month() have bad query performance Env: db2 LUW V8 + FP14 Problem : We have history data from 2005/01/01 ~ 2007/05/xx in single big table, we try separate this big table into twelve tables and create a view
4
13846
by: Theo R. | last post by:
Hi all, I have the following struct defined - #define INTEGER 0 #define STRING 1 typedef struct { char type ; union {
4
10548
by: benn686 | last post by:
I have a structure that contains a union that Id like to initialize at compile time... something like: //global declare and initialize fullStructType var1 = { unionMember.union1.field1 = 100; unionMember.union1.field2 = 200 }; fullStructType var2 = { { unionMember.union2 = 300 } , { unionMember.union2 = 400 } };
1
7344
by: r035198x | last post by:
Inspiration Inspired by a post by Jos in the Java forum, I have put together a little article on class initializers. Initializers are indeed underutilized by most Java programmers. Once the Java programmer knows about the constructor he/she feels they have found a good place to put code that must be run before an object is created and sometimes don't try to look for more places to put pre-object creation code. The other places to put...
0
9961
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, weíll explore What is ONU, What Is Router, ONU & Routerís main usage, and What is the difference between ONU and Router. Letís take a closer look ! Part I. Meaning of...
0
11187
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10783
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10887
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10439
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7148
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
1
4642
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
4248
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
3252
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.