public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Calling a function with a float argument modifies caller's state.
@ 2012-08-20 23:26 Jeff B
  2012-08-20 23:30 ` Ian Lance Taylor
  2012-08-21 10:32 ` David Brown
  0 siblings, 2 replies; 11+ messages in thread
From: Jeff B @ 2012-08-20 23:26 UTC (permalink / raw)
  To: gcc-help


Hi,

I've run into a problem which appears to be doing an undocumented change
of state in the caller's space when passing float variables to a function,
printf(), which should change nothing in the caller's space. Undocumented
side effects in the caller's space strike me as being very bad.

printf() here is not at fault.  It is the passing of a float variable which
is at fault.  I am compiling with GCC under Linux.  There is some weirdness
going on which I do not understand concerning how floats are passed .  See

     http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl

I originally ran into this problem when I was putting binary values of
various types into a buffer.  When I tried to pass that buffer to printf()
using the proper formatting string for the number's type and a cast on the
buffer to get the right length (but not "(float)") all the printf() formats
worked except for "%f", the output of which was "-nan", ie Not A Number.

I then started asking myself why this did not work.  After all a float is
the same size as an int so why should there be a problem of "%d" vs. "%f"
printf() formats?  Well, I found the aforementioned link which told me this
is probably some weirdness in GCC "C" specific to float function arguments.
Aside from the asymmetry of passing various 32-bit types differently I ran
into something else when I started playing around with it, that being that
a function call using floats which modifies state visible to the caller.

The program below shows there is no problem when passing ints to printf()
but the same code using floats alters something -- has a side-effect which
is visible to the caller.

WHY is a 32-bit float passed to a function in a manner different from a
32-bit int???

I also think that it is a really bad idea to have undocumented side effects
like that.  Or did I already say that?

============================================================================

Here is some version information:

 > uname -a
Linux atomik 2.6.37.6-smp #1 SMP Sat Apr 9 14:01:14 CDT 2011 i686 Intel(R) \
Atom(TM) CPU D510   @ 1.66GHz GenuineIntel GNU/Linux

 > cat /etc/slackware-version
Slackware 13.37.0

 > gcc --version
gcc (GCC) 4.5.2

 > ls -1 /var/log/packages/glib*
/var/log/packages/glib-1.2.10-i486-3
/var/log/packages/glib2-2.28.6-i486-1
/var/log/packages/glibc-2.13-i486-4
/var/log/packages/glibc-i18n-2.13-i486-4
/var/log/packages/glibc-profile-2.13-i486-4
/var/log/packages/glibc-solibs-2.13-i486-4
/var/log/packages/glibc-zoneinfo-2.13-noarch-4
/var/log/packages/glibc-zoneinfo-2011i_2011n-noarch-1


And here is the program followed by its output.  Watch (int)floatVarA change
after successive calls to printf() just passing a float.

============================================================================

// Program to show UNDOCUMENTED side-effects IN THE CALLER'S SPACE when 
passing
// float variables to subroutines which should change NOTHING in the 
caller's
// space.  See 
http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl where
// it says, "In Linux/GCC, double/floating point values should be pushed 
on the
// stack via the x87 pseudo-stack."  I'm not sure but that may be related.

#include <stdio.h>
#include <stdlib.h>

int
main ( int argc, char *argv[])
{
     int   intVarA = 37;
     int   intVarB = 42;

     float floatVarB = 42.0;
     float floatVarA = 37.0;

     // Show where things are and their sizes.

     printf("\nintVarA is at %p of size %d\n", &intVarA, sizeof( intVarA));
     printf("intVarB is at %p of size %d\n", &intVarB, sizeof( intVarB));

     printf("\nfloatVarA is at %p of size %d\n", &floatVarA, sizeof( 
floatVarA));
     printf("floatVarB is at %p of size %d\n", &floatVarB, sizeof( 
floatVarB));

     // Do all the assignments.

     intVarA = 1234;
     intVarB = 5678;

     floatVarA = 1234.0;
     floatVarB = 5678.0;

     // From here on out nothing in main's space should change and for
     // calls with int types it does not ...

     printf( "\n(int)intVarA = %d\n", (int)intVarA); // Prints 1234
     printf( "intVarA = %d\n", intVarA);
     printf( "(int)intVarA = %d\n", (int)intVarA);   // Prints 1234
     printf( "intVarB = %d\n", intVarB);
     printf( "(int)intVarA = %d\n", (int)intVarA);   // Prints 1234
     printf( "intVarA = %d\n", intVarA);

     // ... but something IS changing in MAIN's space with float 
variables.  BAD!

     printf( "\n(int)floatVarA = %f\n", (int)floatVarA); // Prints 0.0
     printf( "floatVarA = %f\n", floatVarA);
     printf( "(int)floatVarA = %f\n", (int)floatVarA);   // Prints 1234.0
     printf( "floatVarB = %f\n", floatVarB);
     printf( "(int)floatVarA = %f\n", (int)floatVarA);   // Prints 5678.0
     printf( "floatVarA = %f\n", floatVarA);

     return 0;
}

============================================================================

 > cc float_passing_insanity.c && ./a.out

intVarA is at 0xbf80155c of size 4
intVarB is at 0xbf801558 of size 4

floatVarA is at 0xbf801550 of size 4
floatVarB is at 0xbf801554 of size 4

(int)intVarA = 1234
intVarA = 1234
(int)intVarA = 1234
intVarB = 5678
(int)intVarA = 1234
intVarA = 1234

(int)floatVarA = 0.000000
floatVarA = 1234.000000
(int)floatVarA = 1234.000000
floatVarB = 5678.000000
(int)floatVarA = 5678.000000
floatVarA = 1234.000000

============================================================================

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-20 23:26 Calling a function with a float argument modifies caller's state Jeff B
@ 2012-08-20 23:30 ` Ian Lance Taylor
  2012-08-21 10:32 ` David Brown
  1 sibling, 0 replies; 11+ messages in thread
From: Ian Lance Taylor @ 2012-08-20 23:30 UTC (permalink / raw)
  To: Jeff B; +Cc: gcc-help

On Mon, Aug 20, 2012 at 1:21 PM, Jeff B <a.GNUbie@myletters.us> wrote:
>
>     printf( "\n(int)floatVarA = %f\n", (int)floatVarA); // Prints 0.0

You are printing a value of int type using %f.  Don't do that.

Ian

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-20 23:26 Calling a function with a float argument modifies caller's state Jeff B
  2012-08-20 23:30 ` Ian Lance Taylor
@ 2012-08-21 10:32 ` David Brown
  2012-08-21 15:54   ` Ángel González
  1 sibling, 1 reply; 11+ messages in thread
From: David Brown @ 2012-08-21 10:32 UTC (permalink / raw)
  To: Jeff B; +Cc: gcc-help

On 20/08/2012 22:21, Jeff B wrote:
>
> Hi,
>
> I've run into a problem which appears to be doing an undocumented change
> of state in the caller's space when passing float variables to a function,
> printf(), which should change nothing in the caller's space. Undocumented
> side effects in the caller's space strike me as being very bad.
>
> printf() here is not at fault.  It is the passing of a float variable which
> is at fault.  I am compiling with GCC under Linux.  There is some weirdness
> going on which I do not understand concerning how floats are passed .  See
>
>      http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl
>
> I originally ran into this problem when I was putting binary values of
> various types into a buffer.  When I tried to pass that buffer to printf()
> using the proper formatting string for the number's type and a cast on the
> buffer to get the right length (but not "(float)") all the printf() formats
> worked except for "%f", the output of which was "-nan", ie Not A Number.
>
> I then started asking myself why this did not work.  After all a float is
> the same size as an int so why should there be a problem of "%d" vs. "%f"
> printf() formats?  Well, I found the aforementioned link which told me this
> is probably some weirdness in GCC "C" specific to float function arguments.
> Aside from the asymmetry of passing various 32-bit types differently I ran
> into something else when I started playing around with it, that being that
> a function call using floats which modifies state visible to the caller.
>
> The program below shows there is no problem when passing ints to printf()
> but the same code using floats alters something -- has a side-effect which
> is visible to the caller.
>
> WHY is a 32-bit float passed to a function in a manner different from a
> 32-bit int???
>

A 32-bit float and a 32-bit int are completely different things.  The 
fact that the have a common size is just coincidence.  The compiler can 
treat them totally differently - on many targets (including, I believe, 
the x86 - depending on the compiler flags) they will be passed around in 
different registers.  If it suits the cpu in question, the compiler can 
happily convert the 32-bit float to a 64-bit (or even higher) resolution 
before passing it around.  You certainly cannot rely on being able to 
convert randomly between ints and floats while keeping the same exact 
values.

When passing data into printf(), the compiler can take the actual format 
string into account.  When you write "printf("%f", x)", you are /not/ 
saying "pass a 32-bit value x, treat it as representing a float, and 
print it".  The compiler may /choose/ to treat it that way.  But it can 
also validly interpret it as "treat the value x as a float, and print it 
out".  When you use C properly, according to the specifications of 
printf, these do the same thing - but one way might do it with smaller 
or faster code, or with better static error checking.  When you break C 
rules by your mixed casting, they can mean different things.

> I also think that it is a really bad idea to have undocumented side effects
> like that.  Or did I already say that?
>

I think most people will agree that undocumented side effects are a bad 
idea.  But your program does not demonstrate undocumented side effects.

Your program demonstrates that when you write code that has undefined 
behaviour, it does not work as you expect.  That should not be a big 
surprise.

You also don't demonstrate that the calls to printf are modifying the 
caller's state.  My immediate interpretation of your result is that the 
compiler is doing alias analysis - it knows what can and cannot be 
legally done in conversions between unrelated types (int and float), and 
it uses this knowledge to generate code that is more optimal under the 
assumption that the programmer is following the rules of C.  When you 
break those rules, you break that assumption - lie to your compiler and 
you will get bad code as a result.


Try compiling your code with -Wall, which will help point out your errors.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-21 10:32 ` David Brown
@ 2012-08-21 15:54   ` Ángel González
  2012-08-21 21:11     ` Jeff B
  0 siblings, 1 reply; 11+ messages in thread
From: Ángel González @ 2012-08-21 15:54 UTC (permalink / raw)
  To: David Brown; +Cc: Jeff B, gcc-help

On 21/08/12 08:40, David Brown wrote:
> On 20/08/2012 22:21, Jeff B wrote:
>> (...)
>>
>> WHY is a 32-bit float passed to a function in a manner different from a
>> 32-bit int???
>>
>
> A 32-bit float and a 32-bit int are completely different things.  The
> fact that the have a common size is just coincidence.  The compiler
> can treat them totally differently - on many targets (including, I
> believe, the x86 - depending on the compiler flags) they will be
> passed around in different registers.  If it suits the cpu in
> question, the compiler can happily convert the 32-bit float to a
> 64-bit (or even higher) resolution before passing it around.  You
> certainly cannot rely on being able to convert randomly between ints
> and floats while keeping the same exact values.
>
> When passing data into printf(), the compiler can take the actual
> format string into account.  When you write "printf("%f", x)", you are
> /not/ saying "pass a 32-bit value x, treat it as representing a float,
> and print it".  The compiler may /choose/ to treat it that way.  But
> it can also validly interpret it as "treat the value x as a float, and
> print it out".  When you use C properly, according to the
> specifications of printf, these do the same thing - but one way might
> do it with smaller or faster code, or with better static error
> checking.  When you break C rules by your mixed casting, they can mean
> different things.
>
>> I also think that it is a really bad idea to have undocumented side
>> effects
>> like that.  Or did I already say that?
>>
>
> I think most people will agree that undocumented side effects are a
> bad idea.  But your program does not demonstrate undocumented side
> effects.
>
> Your program demonstrates that when you write code that has undefined
> behaviour, it does not work as you expect.  That should not be a big
> surprise.
>
> You also don't demonstrate that the calls to printf are modifying the
> caller's state.  My immediate interpretation of your result is that
> the compiler is doing alias analysis - it knows what can and cannot be
> legally done in conversions between unrelated types (int and float),
> and it uses this knowledge to generate code that is more optimal under
> the assumption that the programmer is following the rules of C.  When
> you break those rules, you break that assumption - lie to your
> compiler and you will get bad code as a result.
>
>
> Try compiling your code with -Wall, which will help point out your
> errors.

Compiling with -Wall it will complain about passing an int to a %f
parameter.
The program shown by Jeff is consistent with printf(..., float) moving
the value to a float register and printf("%f") printing the code from
that register.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-21 15:54   ` Ángel González
@ 2012-08-21 21:11     ` Jeff B
  2012-08-21 21:38       ` David Brown
                         ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Jeff B @ 2012-08-21 21:11 UTC (permalink / raw)
  To: Ángel González, David Brown; +Cc: gcc-help, Jeff B


Thank you for your replies.  My responses are below.


>>> On 20/08/2012 22:21, Jeff B wrote:
>>>
>>> (...)
>>>
>>> WHY is a 32-bit float passed to a function in a manner different from a
>>> 32-bit int???
>> On 21/08/12 08:40, David Brown wrote:
>>
>> A 32-bit float and a 32-bit int are completely different things.

I am completely aware of that.


>> The
>> fact that the have a common size is just coincidence.  The compiler
>> can treat them totally differently -

Obviously it is treating them very differently.


>> on many targets (including, I
>> believe, the x86 - depending on the compiler flags) they will be
>> passed around in different registers.  If it suits the cpu in
>> question, the compiler can happily convert the 32-bit float to a
>> 64-bit (or even higher) resolution before passing it around.  You
>> certainly cannot rely on being able to convert randomly between ints
>> and floats while keeping the same exact values.

I am completely aware of the limitations of conversions.
That is not the issue.


>> When passing data into printf(), the compiler can take the actual
>> format string into account.

I am aware of that too.  I am not concerned that the output might
be garbled.



>> When you write "printf("%f", x)", you are
>> /not/ saying "pass a 32-bit value x, treat it as representing a float,
>> and print it".

I considered that too, but that is not the issue.  I can understand
that the value might get printed out in some way I didn't expect.


>> The compiler may /choose/ to treat it that way.  But
>> it can also validly interpret it as "treat the value x as a float, and
>> print it out".  When you use C properly, according to the
>> specifications of printf, these do the same thing - but one way might
>> do it with smaller or faster code, or with better static error
>> checking.  When you break C rules by your mixed casting, they can mean
>> different things.
>>
>>> I also think that it is a really bad idea to have undocumented side
>>> effects
>>> like that.  Or did I already say that?
>>>
>> I think most people will agree that undocumented side effects are a
>> bad idea.  But your program does not demonstrate undocumented side
>> effects.

Well, a variable I am able to access from main() is changing
even tho there is nothing in main() itself which is changing it.
I do not change the variables after I init them:

     floatVarA = 1234.0;
     floatVarB = 5678.0;


(int)floatVarA = 0.000000            <<=== initial value 0??
floatVarA = 1234.000000
(int)floatVarA = 1234.000000     <<=== changed
floatVarB = 5678.000000
(int)floatVarA = 5678.000000    <<=== changed again
floatVarA = 1234.000000


The only thing I am doing is calling printf() and passing the
variables by value.  Neither am I using any printf() format
which is going to send data back to main(), eg %n.  So why
is something visible to main() changing, however esoteric?

BTW I was originally putting values into a small array of
doubles (to force alignment) so that I could print them out
in hex, which is not an unreasonable thing to do.  Then I tried
to print the actual values with proper interpretation  from
said buffer using the proper printf() format and with proper
casts, which is also not an unreasonable thing to do.  Casting
as float with printf() format %f failed that exercise, outputting
"-nan".

When I started poking at it that's when I discovered that passing
a float variable (or float constant) was causing a value to change
in main().  The equivalent code with the same sized ints does not
exhibit that behavior.


>> Your program demonstrates that when you write code that has undefined
>> behaviour, it does not work as you expect.  That should not be a big
>> surprise.

I agree about using code with undefined behavior.  Regardless
of whatever confusion printf() may have about how to actually
print something, it seems to me that (int)floatVar  ought to be
getting the bits from the same place as (float)floatVar.  Is that
not true?

Yet clearly the bits are being fetched from elsewhere. When I
print floatVarA as a float its value is correct and unchanging.
When I cast that same 32-bit variable to int the code is clearly
looking at something which is changing and which therefore
must be something other than the 32 floatVarA bits which are
demonstrably NOT changing.

Maybe that is the issue.  Maybe (int)floatVarA   IS   looking at
something outside of the scope of main() which might reasonably
be expected to change.  But if that is the case then the cast is going
to the wrong place.  The variable, however cast, should be fetched
from the same location in memory whatever confusion might then
result in the interpretation of the fetched bits.  Yes?


>>
>> You also don't demonstrate that the calls to printf are modifying the
>> caller's state.

(int)floatVarA = 0.000000            <<=== initial value 0??
floatVarA = 1234.000000
(int)floatVarA = 1234.000000     <<=== changed
floatVarB = 5678.000000
(int)floatVarA = 5678.000000    <<=== changed again
floatVarA = 1234.000000

>> My immediate interpretation of your result is that
>> the compiler is doing alias analysis - it knows what can and cannot be
>> legally done in conversions between unrelated types (int and float),

Again I am not concerned with the misinterpretation of the bits,
just which location are those bits coming from.


>> and it uses this knowledge to generate code that is more optimal under
>> the assumption that the programmer is following the rules of C.  When
>> you break those rules, you break that assumption - lie to your
>> compiler and you will get bad code as a result.
>>
>>
>> Try compiling your code with -Wall, which will help point out your
>> errors.
> On 08/21/2012 10:20 AM, Ángel González wrote:
>
> Compiling with -Wall it will complain about passing an int to a %f
> parameter.
> The program shown by Jeff is consistent with printf(..., float) moving
> the value to a float register and printf("%f") printing the code from
> that register.

I guess, in summary, my question is now, "Does re-casting a variable
ever cause data (however misinterpreted) to be fetched from a different
location?"  I should think it would not.

Again, thank you for your replies.

Jeff Barry


PS: My eMail address, a.GNUbie@myLetters.US, is meant to imply that
I am new to the specifics of GNU.  I am hardly new to low level coding
in case my eMail address implied that to you.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-21 21:11     ` Jeff B
@ 2012-08-21 21:38       ` David Brown
  2012-08-22  9:04       ` Ian Lance Taylor
  2012-08-22 10:56       ` Andrew Haley
  2 siblings, 0 replies; 11+ messages in thread
From: David Brown @ 2012-08-21 21:38 UTC (permalink / raw)
  To: Jeff B; +Cc: Ángel González, David Brown, gcc-help

On 21/08/12 19:40, Jeff B wrote:
>
> Thank you for your replies. My responses are below.
>
>
>>>> On 20/08/2012 22:21, Jeff B wrote:
>>>>
>>>> (...)
>>>>
>>>> WHY is a 32-bit float passed to a function in a manner different from a
>>>> 32-bit int???
>>> On 21/08/12 08:40, David Brown wrote:
>>>
>>> A 32-bit float and a 32-bit int are completely different things.
>
> I am completely aware of that.
>
>
>>> The
>>> fact that the have a common size is just coincidence. The compiler
>>> can treat them totally differently -
>
> Obviously it is treating them very differently.
>
>
>>> on many targets (including, I
>>> believe, the x86 - depending on the compiler flags) they will be
>>> passed around in different registers. If it suits the cpu in
>>> question, the compiler can happily convert the 32-bit float to a
>>> 64-bit (or even higher) resolution before passing it around. You
>>> certainly cannot rely on being able to convert randomly between ints
>>> and floats while keeping the same exact values.
>
> I am completely aware of the limitations of conversions.
> That is not the issue.
>
>
>>> When passing data into printf(), the compiler can take the actual
>>> format string into account.
>
> I am aware of that too. I am not concerned that the output might
> be garbled.
>
>
>
>>> When you write "printf("%f", x)", you are
>>> /not/ saying "pass a 32-bit value x, treat it as representing a float,
>>> and print it".
>
> I considered that too, but that is not the issue. I can understand
> that the value might get printed out in some way I didn't expect.
>
>
>>> The compiler may /choose/ to treat it that way. But
>>> it can also validly interpret it as "treat the value x as a float, and
>>> print it out". When you use C properly, according to the
>>> specifications of printf, these do the same thing - but one way might
>>> do it with smaller or faster code, or with better static error
>>> checking. When you break C rules by your mixed casting, they can mean
>>> different things.
>>>
>>>> I also think that it is a really bad idea to have undocumented side
>>>> effects
>>>> like that. Or did I already say that?
>>>>
>>> I think most people will agree that undocumented side effects are a
>>> bad idea. But your program does not demonstrate undocumented side
>>> effects.
>
> Well, a variable I am able to access from main() is changing
> even tho there is nothing in main() itself which is changing it.

It is perhaps a matter of semantics, but you have not demonstrated that 
your calls to printf are changing main's variables in any way.  The 
effect you are seeing is consistent with the theory that the compiler is 
making assumptions based on the types of the variables and their uses, 
that would be correct if the C code were legal - but are causing strange 
effects on your undefined code.

> I do not change the variables after I init them:
>
> floatVarA = 1234.0;
> floatVarB = 5678.0;
>
>
> (int)floatVarA = 0.000000 <<=== initial value 0??
> floatVarA = 1234.000000
> (int)floatVarA = 1234.000000 <<=== changed
> floatVarB = 5678.000000
> (int)floatVarA = 5678.000000 <<=== changed again
> floatVarA = 1234.000000
>
>
> The only thing I am doing is calling printf() and passing the
> variables by value. Neither am I using any printf() format
> which is going to send data back to main(), eg %n. So why
> is something visible to main() changing, however esoteric?

(Assuming my theory here is correct...)
The values are /not/ changing - the compiler is generating code that 
would be correct if your code had been legal C.

One of the most obvious possibilities here is that the compiler is 
putting floats into MMX registers, and integers into integer registers. 
  When you call printf with a "%f" parameter, it prints out the value 
that is in the appropriate MMX register - but because you have been 
passing "int" data, it has been passed in an integer register.

You can see that the variables have not been changed or corrupted 
because when you print them out legally (without the casts), you get the 
expected results.

>
> BTW I was originally putting values into a small array of
> doubles (to force alignment) so that I could print them out
> in hex, which is not an unreasonable thing to do. Then I tried

It /is/ an unreasonable thing to do, if you are trying to cast like 
this.  You need to use a type-punning union to convert the data safely, 
or use an memcpy().

> to print the actual values with proper interpretation from
> said buffer using the proper printf() format and with proper
> casts, which is also not an unreasonable thing to do. Casting
> as float with printf() format %f failed that exercise, outputting
> "-nan".
>
> When I started poking at it that's when I discovered that passing
> a float variable (or float constant) was causing a value to change
> in main(). The equivalent code with the same sized ints does not
> exhibit that behavior.
>

It is legal to cast same-sized ints like this, so the code works as you 
want.

>
>>> Your program demonstrates that when you write code that has undefined
>>> behaviour, it does not work as you expect. That should not be a big
>>> surprise.
>
> I agree about using code with undefined behavior. Regardless
> of whatever confusion printf() may have about how to actually
> print something, it seems to me that (int)floatVar ought to be
> getting the bits from the same place as (float)floatVar. Is that
> not true?

No, it is not true - which is the heart of your problem.  Integer 
registers and floating point registers can be completely independent. 
And even if the data is in memory, the compiler can assume they are 
independent because integers cannot alias floats.

>
> Yet clearly the bits are being fetched from elsewhere. When I
> print floatVarA as a float its value is correct and unchanging.
> When I cast that same 32-bit variable to int the code is clearly
> looking at something which is changing and which therefore
> must be something other than the 32 floatVarA bits which are
> demonstrably NOT changing.

True.

>
> Maybe that is the issue. Maybe (int)floatVarA IS looking at
> something outside of the scope of main() which might reasonably
> be expected to change. But if that is the case then the cast is going
> to the wrong place. The variable, however cast, should be fetched
> from the same location in memory whatever confusion might then
> result in the interpretation of the fetched bits. Yes?

No.  (See above.)

>
>
>>>
>>> You also don't demonstrate that the calls to printf are modifying the
>>> caller's state.
>
> (int)floatVarA = 0.000000 <<=== initial value 0??
> floatVarA = 1234.000000
> (int)floatVarA = 1234.000000 <<=== changed
> floatVarB = 5678.000000
> (int)floatVarA = 5678.000000 <<=== changed again
> floatVarA = 1234.000000
>

As noted before, this does not demonstrate that the caller's state is in 
any way modified - only that your undefined printf calls do not work in 
the way you expect (while the legal ones do work as intended).

>>> My immediate interpretation of your result is that
>>> the compiler is doing alias analysis - it knows what can and cannot be
>>> legally done in conversions between unrelated types (int and float),
>
> Again I am not concerned with the misinterpretation of the bits,
> just which location are those bits coming from.
>
>
>>> and it uses this knowledge to generate code that is more optimal under
>>> the assumption that the programmer is following the rules of C. When
>>> you break those rules, you break that assumption - lie to your
>>> compiler and you will get bad code as a result.
>>>
>>>
>>> Try compiling your code with -Wall, which will help point out your
>>> errors.
>> On 08/21/2012 10:20 AM, Ángel González wrote:
>>
>> Compiling with -Wall it will complain about passing an int to a %f
>> parameter.
>> The program shown by Jeff is consistent with printf(..., float) moving
>> the value to a float register and printf("%f") printing the code from
>> that register.
>
> I guess, in summary, my question is now, "Does re-casting a variable
> ever cause data (however misinterpreted) to be fetched from a different
> location?" I should think it would not.
>

Sorry to shatter your illusions!

> Again, thank you for your replies.
>
> Jeff Barry
>
>
> PS: My eMail address, a.GNUbie@myLetters.US, is meant to imply that
> I am new to the specifics of GNU. I am hardly new to low level coding
> in case my eMail address implied that to you.
>

If you are familiar with x86 assembly code, have a look at the assembly 
listing.  It might help you get a feel for what is going on here.

Also remember that being experienced at low-level coding doesn't mean 
you haven't missed something.  A lot of people who had been coding for 
years or decades (such as myself) get caught out by the alias analysis 
done by more modern compilers - indeed it is the low-level experts who 
use these sort of casting tricks that get caught by smarter compilers. 
I certainly know I have written code in the past that would not work on 
a modern gcc because of this sort of thing.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-21 21:11     ` Jeff B
  2012-08-21 21:38       ` David Brown
@ 2012-08-22  9:04       ` Ian Lance Taylor
  2012-08-22 10:56       ` Andrew Haley
  2 siblings, 0 replies; 11+ messages in thread
From: Ian Lance Taylor @ 2012-08-22  9:04 UTC (permalink / raw)
  To: Jeff B; +Cc: Ángel González, David Brown, gcc-help

On Tue, Aug 21, 2012 at 10:40 AM, Jeff B <a.GNUbie@myletters.us> wrote:
>
> Well, a variable I am able to access from main() is changing
> even tho there is nothing in main() itself which is changing it.

Your program does not demonstrate that that has happened.

> I agree about using code with undefined behavior.  Regardless
> of whatever confusion printf() may have about how to actually
> print something, it seems to me that (int)floatVar  ought to be
> getting the bits from the same place as (float)floatVar.  Is that
> not true?

It is not true.

To understand why it is not true, see the x86 calling conventions.
They pass int and float arguments in different places.

Ian

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-21 21:11     ` Jeff B
  2012-08-21 21:38       ` David Brown
  2012-08-22  9:04       ` Ian Lance Taylor
@ 2012-08-22 10:56       ` Andrew Haley
  2012-08-22 14:07         ` Jeff B
  2 siblings, 1 reply; 11+ messages in thread
From: Andrew Haley @ 2012-08-22 10:56 UTC (permalink / raw)
  To: Jeff B; +Cc: Ángel González, David Brown, gcc-help

On 08/21/2012 06:40 PM, Jeff B wrote:
> (int)floatVarA = 0.000000            <<=== initial value 0??

The initial value is zero because there is garbage in Float Register 0.

> floatVarA = 1234.000000

Now Float Register 0 contains 1234.0 .

> (int)floatVarA = 1234.000000     <<=== changed

Which gets printed out.

> floatVarB = 5678.000000

Now Float Register 0 contains 5678.0 .

> (int)floatVarA = 5678.000000    <<=== changed again

Which gets printed out.

> floatVarA = 1234.000000

etc...

Moral: undefined behaviour can do anything.

Andrew.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-22 10:56       ` Andrew Haley
@ 2012-08-22 14:07         ` Jeff B
  2012-08-22 14:41           ` Ian Lance Taylor
  2012-08-22 15:34           ` David Brown
  0 siblings, 2 replies; 11+ messages in thread
From: Jeff B @ 2012-08-22 14:07 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Ángel González, David Brown, gcc-help


>> On 08/21/2012 06:40 PM, Jeff B wrote:
>>
>>
>> (int)floatVarA = 0.000000            <<=== initial value 0??
> On 08/22/2012 03:50 AM, Andrew Haley wrote:
>
> The initial value is zero because there is garbage in Float Register 0.
>
>> floatVarA = 1234.000000
> Now Float Register 0 contains 1234.0 .
>
>> (int)floatVarA = 1234.000000     <<=== changed
> Which gets printed out.
>
>> floatVarB = 5678.000000
> Now Float Register 0 contains 5678.0 .
>
>> (int)floatVarA = 5678.000000    <<=== changed again
> Which gets printed out.
>
>> floatVarA = 1234.000000
> etc...
>
> Moral: undefined behaviour can do anything.
>
> Andrew.


OK, then I guess the presence of the cast makes it OK for the compiler
to pull the bits for a variable from somewhere other than where the
variable actually is.

So, while we are at it, what other casts should I avoid?

Thanks.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-22 14:07         ` Jeff B
@ 2012-08-22 14:41           ` Ian Lance Taylor
  2012-08-22 15:34           ` David Brown
  1 sibling, 0 replies; 11+ messages in thread
From: Ian Lance Taylor @ 2012-08-22 14:41 UTC (permalink / raw)
  To: Jeff B; +Cc: Andrew Haley, Ángel González, David Brown, gcc-help

On Wed, Aug 22, 2012 at 6:58 AM, Jeff B <a.GNUbie@myletters.us> wrote:
>
> OK, then I guess the presence of the cast makes it OK for the compiler
> to pull the bits for a variable from somewhere other than where the
> variable actually is.

No.

As I said before, the problem is the calling convention.  printf with
%f expects a float argument.  You are passing it an int argument.  A
float argument is passed in a float register.  An int argument is
passed in a general register.  printf sees %f and looks in a float
register.  You are passing the value in an int register.  Since you
are not passing the value in a float register, printf is printing
random bits that you never passed.

Ian

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Calling a function with a float argument modifies caller's state.
  2012-08-22 14:07         ` Jeff B
  2012-08-22 14:41           ` Ian Lance Taylor
@ 2012-08-22 15:34           ` David Brown
  1 sibling, 0 replies; 11+ messages in thread
From: David Brown @ 2012-08-22 15:34 UTC (permalink / raw)
  To: Jeff B; +Cc: Andrew Haley, Ángel González, gcc-help

On 22/08/2012 15:58, Jeff B wrote:
>
>>> On 08/21/2012 06:40 PM, Jeff B wrote:
>>>
>>>
>>> (int)floatVarA = 0.000000            <<=== initial value 0??
>> On 08/22/2012 03:50 AM, Andrew Haley wrote:
>>
>> The initial value is zero because there is garbage in Float Register 0.
>>
>>> floatVarA = 1234.000000
>> Now Float Register 0 contains 1234.0 .
>>
>>> (int)floatVarA = 1234.000000     <<=== changed
>> Which gets printed out.
>>
>>> floatVarB = 5678.000000
>> Now Float Register 0 contains 5678.0 .
>>
>>> (int)floatVarA = 5678.000000    <<=== changed again
>> Which gets printed out.
>>
>>> floatVarA = 1234.000000
>> etc...
>>
>> Moral: undefined behaviour can do anything.
>>
>> Andrew.
>
>
> OK, then I guess the presence of the cast makes it OK for the compiler
> to pull the bits for a variable from somewhere other than where the
> variable actually is.
>
> So, while we are at it, what other casts should I avoid?
>
> Thanks.
>

You are still missing the point.

Avoid writing code with undefined behaviour.  Do not lie to your 
compiler.  Do not tell it "here is a float" and pass it an integer.  Use 
"-Wall" to let the compiler help you avoid such mistakes.

It is perfectly okay to cast a float to an int - but it is not okay to 
do so and then expect the compiler to treat it as a float.  So you can 
write this:

	printf("(int) floatVarA = %d\n", (int) floatVarA);

Then you are casting the float to an int legally (1234.0 will turn into 
1234), then passing that int to printf, with a format string that tells 
printf to expect an int and print it out.


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2012-08-22 14:41 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-20 23:26 Calling a function with a float argument modifies caller's state Jeff B
2012-08-20 23:30 ` Ian Lance Taylor
2012-08-21 10:32 ` David Brown
2012-08-21 15:54   ` Ángel González
2012-08-21 21:11     ` Jeff B
2012-08-21 21:38       ` David Brown
2012-08-22  9:04       ` Ian Lance Taylor
2012-08-22 10:56       ` Andrew Haley
2012-08-22 14:07         ` Jeff B
2012-08-22 14:41           ` Ian Lance Taylor
2012-08-22 15:34           ` David Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).