Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Address of a union member

Reply
Thread Tools

Address of a union member

 
 
Noob
Guest
Posts: n/a
 
      08-13-2009
Hello,

My compiler complains when I take the address of a member in a union.

$ cat mu.c
union foo
{
int i;
double d;
};

int main(void)
{
union foo bar = { 0 };
int *p = &(bar.i);
return *p;
}

$ cc mu.c
w "mu.c",L10/C12(#241): Address of a union member is being used as a
| pointer. This may violate an assumption made by the optimizer.
| To be safe, you should recompile your program at a lower
| optimization level; or else, turn off the BEHAVED toggle.
No errors 1 warning

I don't see what the problem is, and gcc did not seem to mind.

$ gcc -O2 -std=c89 -Wall -Wextra mu.c
/* NO OUTPUT */

Is this an aliasing problem?

What am I doing wrong?

Regards.
 
Reply With Quote
 
 
 
 
Noob
Guest
Posts: n/a
 
      08-13-2009
Eric Sosman wrote:
> Noob wrote:
>> Hello,
>>
>> My compiler complains when I take the address of a member in a union.
>>
>> $ cat mu.c
>> union foo
>> {
>> int i;
>> double d;
>> };
>>
>> int main(void)
>> {
>> union foo bar = { 0 };
>> int *p = &(bar.i);
>> return *p;
>> }
>>
>> $ cc mu.c
>> w "mu.c",L10/C12(#241): Address of a union member is being used as a
>> | pointer. This may violate an assumption made by the optimizer.
>> | To be safe, you should recompile your program at a lower
>> | optimization level; or else, turn off the BEHAVED toggle.
>> No errors 1 warning
>>
>> I don't see what the problem is, and gcc did not seem to mind.
>>
>> $ gcc -O2 -std=c89 -Wall -Wextra mu.c
>> /* NO OUTPUT */
>>
>> Is this an aliasing problem?
>>
>> What am I doing wrong?

>
> Nothing that I can see. My guess is that the compiler wants
> to assume that an int* and a double* point to different objects
> since they point to different types. That is, if you pass both
> &bar.i and &bar.d as arguments to
>
> void silly(int *ip, double *dp) {
> *ip = 42;
> *dp = 42.0;
> *ip = 42;
> }
>
> ... the compiler might assume that the two differently-typed
> parameters point to two differently-typed and distinct objects,
> so the third assignment could be omitted.
>
> ... but if I were you, I'd read my compiler's documentation
> starting with what it says about "the BEHAVED toggle."


Good advice

"""
When it assumes that code is well-behaved, the compiler can be less conservative
in generating code for pointer-based objects. Well-behaved code follows these rules:

o The address of a union member is never assigned to a pointer.
o A value of a pointer type is never cast to an incompatible pointer type.

Given these assumptions, the compiler might be able to generate substantially
better code in referencing pointer-based variables. The compiler issues an
appropriate warning if either of these assumptions is violated in such a way as
to affect assumptions made by the optimizer. You must decide whether the
warnings can be safely ignored or whether the program should be compiled at a
lower optimization level.

CAUTION: The compiler might not catch all instances of misbehaved code.
For example, a pointer-to-char might be passed to an undeclared
(unprototyped) external function expecting a pointer-to-int.
Therefore, it is possible for a program to compile at optimization
level 6 without warnings (and run incorrectly), but run correctly
when compiled at a lower optimization level.
"""

I'm not sure what they mean by "You must decide whether the warnings can be
safely ignored". How do I tell whether it is safe?

Regards.

 
Reply With Quote
 
 
 
 
Ben Bacarisse
Guest
Posts: n/a
 
      08-13-2009
Noob <root@127.0.0.1> writes:

> My compiler complains when I take the address of a member in a union.
>
> $ cat mu.c
> union foo
> {
> int i;
> double d;
> };
>
> int main(void)
> {
> union foo bar = { 0 };
> int *p = &(bar.i);
> return *p;
> }
>
> $ cc mu.c
> w "mu.c",L10/C12(#241): Address of a union member is being used as a
> | pointer. This may violate an assumption made by the optimizer.
> | To be safe, you should recompile your program at a lower
> | optimization level; or else, turn off the BEHAVED toggle.
> No errors 1 warning
>
> I don't see what the problem is, and gcc did not seem to mind.
>
> $ gcc -O2 -std=c89 -Wall -Wextra mu.c
> /* NO OUTPUT */
>
> Is this an aliasing problem?


I think so, yes. In section 6.5 you will find:

7 An object shall have its stored value accessed only by an lvalue
expression that has one of the following types[76]

— a type compatible with the effective type of the object,

— a qualified version of a type compatible with the effective type
of the object,

— a type that is the signed or unsigned type corresponding to the
effective type of the object,

— a type that is the signed or unsigned type corresponding to a
qualified version of the effective type of the object,

— an aggregate or union type that includes one of the aforementioned
types among its members (including, recursively, a member of a
subaggregate or contained union), or

— a character type.

Footnote 76 is: "The intent of this list is to specify those
circumstances in which an object may or may not be aliased."

The compiler is warning you that I can assume that the union (in
particular the other member) will not change as a result of changes
though the pointer you have just obtained.

There in not problem in taking the address, but the compiler can
assume that *p does not change when u.d changes (and vice versa).
This is often called the "strict aliasing rule".

--
Ben.
 
Reply With Quote
 
phil-news-nospam@ipal.net
Guest
Posts: n/a
 
      08-13-2009
On Thu, 13 Aug 2009 18:30:29 +0200 Noob <root@127.0.0.1> wrote:

| I'm not sure what they mean by "You must decide whether the warnings can be
| safely ignored". How do I tell whether it is safe?

You will have to understand what the optimization does ... on each platform
.... and decide if that optimization will conflict with the behaviour being
coded. For example, in the silly() function shown earlier, is it OK for the
3rd assignment to be skipped?

--
-----------------------------------------------------------------------------
| Phil Howard KA9WGN | http://linuxhomepage.com/ http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/ http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      08-13-2009
Noob <root@127.0.0.1> writes:
> My compiler complains when I take the address of a member in a union.
>
> $ cat mu.c
> union foo
> {
> int i;
> double d;
> };
>
> int main(void)
> {
> union foo bar = { 0 };
> int *p = &(bar.i);
> return *p;
> }
>
> $ cc mu.c
> w "mu.c",L10/C12(#241): Address of a union member is being used as a
> | pointer. This may violate an assumption made by the optimizer.
> | To be safe, you should recompile your program at a lower
> | optimization level; or else, turn off the BEHAVED toggle.
> No errors 1 warning
>
> I don't see what the problem is, and gcc did not seem to mind.

[...]

Compilers are allowed to warn about anything they like.

In this case, the compiler appears to be warning about a *potential*
problem, not one that actually occurs in the code you posted.

Consider, for example:

union foo bar;
int *p = &bar.i;
*p = 10;
bar.d = 12.34;
printf("*p = %d\n", *p);

The optimizer might assume that, since you just stored the value 10 in
*p, the value 10 must still be there, and optimize the printf to
something like puts("p = 10").

(The standard has more to say about whether this behavior is defined
or undefined and whether an optimizer is allowed to make this
assumption; I don't have my copy of the standard handy right now and
I'm too lazy to look it up.)

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      08-13-2009
Eric Sosman <(E-Mail Removed)> wrote:
> Noob wrote:
> > Hello,
> > My compiler complains when I take the address of a member
> > in a union.

<snip sample>
> > Is this an aliasing problem?

>
> > What am I doing wrong?

>
> * * *Nothing that I can see. *My guess is that the compiler
> wants to assume that an int* and a double* point to different
> objects since they point to different types. *That is, if you
> pass both &bar.i and &bar.d as arguments to
>
> * * * * void silly(int *ip, double *dp) {
> * * * * * * *ip = 42;
> * * * * * * *dp = 42.0;
> * * * * * * *ip = 42;
> * * * * }
>
> ... the compiler might assume that the two differently-typed
> parameters point to two differently-typed and distinct objects,
> so the third assignment could be omitted.


The first perhaps, but not the third. Strictly conforming code
could detect the difference...

union { int i; double d; } u;
silly(&u.i, &u.d);
printf("%d\n", u.i);

--
Peter
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      08-13-2009
Peter Nilsson <(E-Mail Removed)> writes:

> Eric Sosman <(E-Mail Removed)> wrote:
>> Noob wrote:
>> > Hello,
>> > My compiler complains when I take the address of a member
>> > in a union.

> <snip sample>
>> > Is this an aliasing problem?

>>
>> > What am I doing wrong?

>>
>> * * *Nothing that I can see. *My guess is that the compiler
>> wants to assume that an int* and a double* point to different
>> objects since they point to different types. *That is, if you
>> pass both &bar.i and &bar.d as arguments to
>>
>> * * * * void silly(int *ip, double *dp) {
>> * * * * * * *ip = 42;
>> * * * * * * *dp = 42.0;
>> * * * * * * *ip = 42;
>> * * * * }
>>
>> ... the compiler might assume that the two differently-typed
>> parameters point to two differently-typed and distinct objects,
>> so the third assignment could be omitted.

>
> The first perhaps, but not the third. Strictly conforming code
> could detect the difference...
>
> union { int i; double d; } u;
> silly(&u.i, &u.d);
> printf("%d\n", u.i);


I disagree but given your history of being correct, I currently
suspect that I have missed something here. Does not your snippet of
code violate the "shall" from section 6.5 paragraph 7?

--
Ben.
 
Reply With Quote
 
Nobody
Guest
Posts: n/a
 
      08-14-2009
On Thu, 13 Aug 2009 18:30:29 +0200, Noob wrote:

> I'm not sure what they mean by "You must decide whether the warnings can be
> safely ignored". How do I tell whether it is safe?


Examine the resulting assembler output (or disassembly) to see if it does
what you want.

If you don't understand assembler, either reduce the optimisation level or
avoid constructs which the compiler complains about.

In this case, it looks like the compiler is being overly conservative
about checking for potential aliasing bugs. If you are actually
referencing both union members for the same object, that may well be a bug.

 
Reply With Quote
 
Richard Bos
Guest
Posts: n/a
 
      08-16-2009
Keith Thompson <(E-Mail Removed)> wrote:

> Consider, for example:
>
> union foo bar;
> int *p = &bar.i;
> *p = 10;
> bar.d = 12.34;
> printf("*p = %d\n", *p);
>
> The optimizer might assume that, since you just stored the value 10 in
> *p, the value 10 must still be there, and optimize the printf to
> something like puts("p = 10").
>
> (The standard has more to say about whether this behavior is defined
> or undefined and whether an optimizer is allowed to make this
> assumption; I don't have my copy of the standard handy right now and
> I'm too lazy to look it up.)


You're reading a member of a union which is not the last member that has
been assigned to. You're reading it indirectly, but you're still reading
it. This means that its bytes have unspecified values, and therefore
that its value may be a trap value[1]; hence, in theory undefined
behaviour, but most likely to result in nonsense values. And AFAICT it's
_allowed_ to result in the same nonsense value no matter what you store
in bar.d, or even in different nonsense values even if you store the
same value in bar.d more than once.

Richard

[1] Of the member not last assigned to, _not_ of the union as a, dare I
say it, thing-in-itself.
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      08-17-2009
On Aug 14, 9:36*am, Ben Bacarisse <(E-Mail Removed)> wrote:
> Peter Nilsson <(E-Mail Removed)> writes:
> > Eric Sosman <(E-Mail Removed)> wrote:
> > > * * *...*My guess is that the compiler
> > > wants to assume that an int* and a double* point to
> > > different objects since they point to different types.
> > > That is, if you pass both &bar.i and &bar.d as arguments
> > > to
> > >
> > > * * * * void silly(int *ip, double *dp) {
> > > * * * * * * *ip = 42;
> > > * * * * * * *dp = 42.0;
> > > * * * * * * *ip = 42;
> > > * * * * }
> > >
> > > ... the compiler might assume that the two differently-
> > > typed parameters point to two differently-typed and
> > > distinct objects, so the third assignment could be
> > > omitted.

> >
> > The first perhaps, but not the third. Strictly conforming
> > code could detect the difference...
> >
> > * union { int i; double d; } u;
> > * silly(&u.i, &u.d);
> > * printf("%d\n", u.i);

>
> I disagree but given your history of being correct,


It may have happened. I think it was a Tuesday.

> I currently suspect that I have missed something here. *Does
> not your snippet of code violate the "shall" from section 6.5
> paragraph 7?


I don't see how. The last u.i accesses an object that was last
assigned via an int lvalue. That assigment imposed the
effective type. [6.5p6]

--
Peter
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Multiple union member initialization Ricky Lung C++ 5 08-19-2004 09:07 AM
union in struct without union name Peter Dunker C Programming 2 04-26-2004 07:23 PM
map XML union to C union (and vice-versa) Matt Garman XML 1 04-25-2004 12:40 AM
How would I use qsort to sort a struct with a char* member and a long member - I want to sort in order of the long member Angus Comber C Programming 7 02-05-2004 06:41 PM
Setting union member in structure Jeff Massung C++ 2 12-22-2003 05:53 PM



Advertisments