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>