Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   A basic (?) problem with addresses (gcc) (http://www.velocityreviews.com/forums/t740181-a-basic-problem-with-addresses-gcc.html)

Piotrne 12-15-2010 01:52 PM

A basic (?) problem with addresses (gcc)
 
Hi,

I have a strange problem with casting addresses to different
types. I have a float variable. The sequence of 4 bytes
representing its value should be copied to an int
(of the same size like float: 4 bytes) and then back
to the float variable. Example:

#include <stdio.h>

int main(int argc, char **argv)
{
float x = 4.3;
int y;

y = *(int*)&x; /* copying of 4 bytes to int */
x = *(float*)&y; /* and back to float */

printf("x=%f\n",x); /* 4.3 expected here */
printf("y=%d\n",y);
return 0;
}

I have compiled this example in Linux, using gcc 4.1.1, with
different optimization options. Here are the results:

$ gcc cast2.c
$ ./a.out
x=4.300000
y=1082759578

$ gcc -O2 cast2.c
$ ./a.out
x=-167393728255558576456059409056680378368.000000
y=134513634

The first result is correct, but what happened to the second?
Probably addresses have been shifted for some reason. But such
constructions seem to be an elementary property of the C language,
and they don’t work...

Regards
Piotr

Adrian 12-15-2010 02:49 PM

Re: A basic (?) problem with addresses (gcc)
 
On 12/15/2010 06:52 AM, Piotrne wrote:
> Hi,


> $ gcc cast2.c
> $ ./a.out
> x=4.300000
> y=1082759578
>
> $ gcc -O2 cast2.c
> $ ./a.out
> x=-167393728255558576456059409056680378368.000000
> y=134513634

Hi Piotr

I tried this with gcc.4.5 and both versions produce the same expected
result (and assembler).

Have you tried compiling with -S to check the assembler, maybe 4.1 is
optimizing something away it should not.

I also tried gcc.4.1.1 on x64 and got 0 for the optomized version.

If you try compiling with -S you will see the optimized version has very
different assembler.

gcc.4.1.1 has had a few bugs.

HTH

Adrian Cornish



Morris Keesan 12-15-2010 05:57 PM

Re: A basic (?) problem with addresses (gcc)
 
On Wed, 15 Dec 2010 08:52:41 -0500, Piotrne <piotr23ne@poczta.onet.pl>
wrote:

> Hi,
>
> I have a strange problem with casting addresses to different
> types. I have a float variable. The sequence of 4 bytes
> representing its value should be copied to an int
> (of the same size like float: 4 bytes) and then back
> to the float variable. Example:
>
> #include <stdio.h>
>
> int main(int argc, char **argv)
> {
> float x = 4.3;
> int y;
>
> y = *(int*)&x; /* copying of 4 bytes to int */
> x = *(float*)&y; /* and back to float */
>
> printf("x=%f\n",x); /* 4.3 expected here */
> printf("y=%d\n",y);
> return 0;
> }
>
> I have compiled this example in Linux, using gcc 4.1.1, with
> different optimization options. Here are the results:
>
> $ gcc cast2.c
> $ ./a.out
> x=4.300000
> y=1082759578
>
> $ gcc -O2 cast2.c
> $ ./a.out
> x=-167393728255558576456059409056680378368.000000
> y=134513634
>
> The first result is correct, but what happened to the second?
> Probably addresses have been shifted for some reason. But such
> constructions seem to be an elementary property of the C language,
> and they don’t work...


Casting a pointer to a pointer of a different type is not guaranteed
to work. Worth trying here would be adding the lines

if (sizeof(int) != sizeof(float))
printf("int and float different sizes\n");

if ((void *)&x != (void *)(int *)&x)
printf("Casting &x to (int *) changes its value\n");

if ((void *)&y != (void *)(float *)&x)
printf("Casting &y to (float *) changes its value\n");


The optimizer may be changing the alignment requirements of float and
int objects. If you're trying to copy bytes between incompatible
types, using memcpy() would seem safer and more readable.
But what you're trying to do here seems suspicious, in any case.
--
Morris Keesan -- mkeesan@post.harvard.edu

Piotrne 12-15-2010 07:16 PM

Re: A basic (?) problem with addresses (gcc)
 
Morris Keesan pisze:

> Casting a pointer to a pointer of a different type is not guaranteed
> to work.


The value of the pointer should be retained and is:

Worth trying here would be adding the lines
>
> if (sizeof(int) != sizeof(float))
> printf("int and float different sizes\n");
>
> if ((void *)&x != (void *)(int *)&x)
> printf("Casting &x to (int *) changes its value\n");
>
> if ((void *)&y != (void *)(float *)&x)
> printf("Casting &y to (float *) changes its value\n");


I have checked them (changing x to y in the last "if")
and got no messages, in both compiled versions - in the
optimized, with wrong copying, too.

I have even checked (by printing) values of addresses after
casting to float* or int* - they are the same.

It seems, that the way how the pointer is used to read
memory causes problems. Placing the float variable
in an array (as a middle element of it) changes
the result. Anyway, it is strange. I'll write if I find
something about this.

Piotr




Piotrne 12-15-2010 07:18 PM

Re: A basic (?) problem with addresses (gcc)
 
Morris Keesan wrote:

> Casting a pointer to a pointer of a different type is not guaranteed
> to work.


The value of the pointer should be retained and is:

> Worth trying here would be adding the lines
>
> if (sizeof(int) != sizeof(float))
> printf("int and float different sizes\n");
>
> if ((void *)&x != (void *)(int *)&x)
> printf("Casting &x to (int *) changes its value\n");
>
> if ((void *)&y != (void *)(float *)&x)
> printf("Casting &y to (float *) changes its value\n");


I have checked them (changing x to y in the last "if")
and got no messages, in both compiled versions - in the
optimized, with wrong copying, too.

I have even checked (by printing) values of addresses after
casting to float* or int* - they are the same.

It seems, that the way how the pointer is used to read
memory causes problems. Placing the float variable
in an array (as a middle element of it) changes
the result. Anyway, it is strange. I'll write if I find
something about this.

Piotr

Piotrne 12-15-2010 07:20 PM

Re: A basic (?) problem with addresses (gcc)
 
pete wrote:

> (sizeof (float) == 4) isn't an elementary property
> of the C language.


In this case it is satisfied, I have removed the check
to make the code shorter.

P.



Nick Bowler 12-15-2010 07:45 PM

Re: A basic (?) problem with addresses (gcc)
 
On Wed, 15 Dec 2010 20:18:58 +0100, Piotrne wrote:
> It seems, that the way how the pointer is used to read memory causes
> problems. Placing the float variable in an array (as a middle element
> of it) changes the result. Anyway, it is strange. I'll write if I find
> something about this.


Newer versions of GCC have an optimization called "strict aliasing",
enabled by default at the higher -O levels. It allows the compiler to
assume (among other things) that pointers to int are never used to
access objects of type float and vice versa. Such behaviour is
consistent with the C standard. Violating that assumption will lead
to unpredictable consequences.

Seebs 12-15-2010 07:57 PM

Re: A basic (?) problem with addresses (gcc)
 
On 2010-12-15, Piotrne <piotr23ne@poczta.onet.pl> wrote:
> The first result is correct, but what happened to the second?


Your code was wrong. The compiler did whatever it wanted.

> Probably addresses have been shifted for some reason. But such
> constructions seem to be an elementary property of the C language,
> and they don???t work...


Nope. You invoked undefined behavior, the compiler caught you at it.

Don't do that.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.

Keith Thompson 12-15-2010 08:18 PM

Re: A basic (?) problem with addresses (gcc)
 
Piotrne <piotr23ne@poczta.onet.pl> writes:
> I have a strange problem with casting addresses to different
> types. I have a float variable. The sequence of 4 bytes
> representing its value should be copied to an int
> (of the same size like float: 4 bytes) and then back
> to the float variable. Example:
>
> #include <stdio.h>
>
> int main(int argc, char **argv)
> {
> float x = 4.3;
> int y;
>
> y = *(int*)&x; /* copying of 4 bytes to int */
> x = *(float*)&y; /* and back to float */
>
> printf("x=%f\n",x); /* 4.3 expected here */
> printf("y=%d\n",y);
> return 0;
> }


Your code is at least non-portable. It assumes, among other things,
that int and float are the same size and that they have similar
alignment requirements. Your system (apparently) happens to satisfy
those assumptions, but others may not.

Even so, the compiler may assume that a float* won't be used to access
an int object, and that an int* won't be used to access a float object.

If you really want to copy the representation of one object into an
object of a different type, use memcpy().

What exactly are you trying to accomplish?

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <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"

BartC 12-15-2010 08:45 PM

Re: A basic (?) problem with addresses (gcc)
 


"Seebs" <usenet-nospam@seebs.net> wrote in message
news:slrnigi7cp.14pa.usenet-nospam@guild.seebs.net...
> On 2010-12-15, Piotrne <piotr23ne@poczta.onet.pl> wrote:
>> The first result is correct, but what happened to the second?

>
> Your code was wrong. The compiler did whatever it wanted.
>
>> Probably addresses have been shifted for some reason. But such
>> constructions seem to be an elementary property of the C language,
>> and they don???t work...

>
> Nope. You invoked undefined behavior, the compiler caught you at it.
>


What was wrong with it? Assuming int and float are the same sizes and are
aligned in a compatible way.

--
Bartc




All times are GMT. The time now is 07:33 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.