Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Nov 2002 08:55:02 -0500 (EST)
From:      Thomas David Rivers <rivers@dignus.com>
To:        FreeBSD-current@FreeBSD.ORG, yoshint@flab.fujitsu.co.jp
Subject:   Re: gcc 3.2.1 optimization bug ?
Message-ID:  <200211111355.gABDt2g55397@lakes.dignus.com>
In-Reply-To: <ywlvg34jn21.fsf@cerberus.proc.flab.fujitsu.co.jp>

next in thread | previous in thread | raw e-mail | index | archive | help
> 
> For the source code below, compiling gcc -O2/-O3 seem to produce
> incorrect code.
> 
> -----------------------------------
> #include <stdio.h>
> int main(int argc, char* argv[])
> {
>     unsigned int x = 0x12345678;
>     unsigned short tmp;
>     printf("%x\n", x);
>     tmp = ((unsigned short *)&x)[0];
>     ((unsigned short *)&x)[0] = ((unsigned short *)&x)[1];
>     ((unsigned short *)&x)[1] = tmp;
>     printf("%x\n", x);
>     return 0;
> }
> -----------------------------------
> 
>


 Several people have pointed out that using "volatile" will
 help with your code.

 But - even with the use of "volatile" - your code is invalid ANSI
 C.

 You are doing something called "type punning" - which is illegal.

 Basically, you can't reference a datum via a different type
 and expect it to do anything meaningful.  

 When you take &x, you have and (unsigned int *) type.  When you
 then cast that to an (unsigned short *) and then dereference it,
 you are referencing the datum 'x' via a different type.

 (consider, for example, a situation where `unsigned short' had
 the same alignment requirements as `unsigned int', your example
 would not address what you were thinking...)

 The C99 standard relaxed this rule somewhat, allowing (char *)
 pointers to be used to reference any datum.  So, you could
 use memcpy() to accomplish what you're looking for, as in:

	unsigned short array[2];

	memcpy(array, &x, sizeof(array));

 but - while valid, that also suffers from several issues...

 Your code appears to simply want to swap the two (assumed) words in
 an integer.  That could be accomplished with shifts, etc...
 This code makes all kinds of assumptions about the size of
 `int' and `short' - but represents an alternative approach:

	unsigned int t;
	unsigned int x;

	t = (x & 0xffff) << 16;
	x >>= 16;
	x |= t;

 Assuming `int' was 32-bits wide - this, or something similar,
 might be a more portable approach.
 

 	- Dave Rivers -

--
rivers@dignus.com                        Work: (919) 676-0847
Get your mainframe programming tools at http://www.dignus.com

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200211111355.gABDt2g55397>