Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Undefined behavior - 2 queries

Reply
Thread Tools

Undefined behavior - 2 queries

 
 
Harald van =?UTF-8?B?RMSzaw==?=
Guest
Posts: n/a
 
      09-09-2007
Peter J. Holzer wrote:
> On 2007-09-09 12:56, Harald van Dijk <(E-Mail Removed)> wrote:
>> Peter J. Holzer wrote:
>>> On 2007-09-09 11:51, Army1987 <(E-Mail Removed)> wrote:
>>>> On Sun, 09 Sep 2007 04:37:00 -0700, christian.bau wrote:
>>>>> There is no way in conforming Standard C to access the representation
>>>>> of a float through type int, unsigned int, long or long int, even
>>>>> though this would be very useful.
>>>> float f;
>>>> int i;
>>>> memcpy(&i, &f, sizeof f);
>>>> /* do what you want with i */
>>>> memcpy(&f, &i, sizeof f);
>>>
>>> I don't think this changes anything.

>>
>> It does. One problem with using *(int *) &f, simplified a bit, is that
>> you're reading and modifying a float using an lvalue of type int. Using
>> memcpy to move f's representation into a real int avoids this one.

>
> I don't think it does. If you think float and int variables are somehow
> special, use malloced memory instead:


The rules for dynamically allocated memory are different. Dynamically
allocated memory gets its effective type from whatever data is stored in
it, while declared objects get their effective types from the declarations.

> void *p1, *p2;
> float *fp;
> int *ip;
>
> assert(sizeof (int) == sizeof (float));
> p1 = malloc(sizeof (float));
> p2 = malloc(sizeof (int));
> fp = p1;
> ip = p2;
> *fp = 42.0;


*fp now has an effective type of float.

> memcpy(p2, p1, sizeof (float));


For dynamically allocated memory (but only for that!), memcpy copies the
effective type of *fp to *ip...

> /* do something with *ip */


....and if you actually do something with *ip here, you're using an lvalue of
type int to read something which has float as its effective type, meaning
the behaviour is not defined by the C standard.

If you had not used malloc, the effective type of int would have been
preserved, because a declared object cannot have its effective type
altered.

> memcpy(p1, p2, sizeof (float));
>
>
> How is this different from
>
> p1 = malloc(sizeof (float));
> fp = p1;
> ip = p1;
> *fp = 42.0;
> /* do something with *ip */
>
> ?


For dynamically allocated memory, there is no difference.

> You are accessing memory with the same content the same way. If the
> sizeof (float) bytes pointed to by p1 are a float which cannot be
> accessed as an integer after the assignment (*fp = 42.0), so are the
> sizeof (float) bytes pointed to by p2 after the first memcpy.


Correct, but this isn't about "a float which cannot be accessed as an
integer". It is already stated as an implementation detail that a float
_can_ be accessed as an integer. This is about how to access it without
violating C's aliasing rules.
 
Reply With Quote
 
 
 
 
Peter J. Holzer
Guest
Posts: n/a
 
      09-09-2007
On 2007-09-09 16:13, Harald van Dijk <(E-Mail Removed)> wrote:
> Peter J. Holzer wrote:
>> On 2007-09-09 12:56, Harald van Dijk <(E-Mail Removed)> wrote:
>>> Peter J. Holzer wrote:
>>>> On 2007-09-09 11:51, Army1987 <(E-Mail Removed)> wrote:
>>>>> On Sun, 09 Sep 2007 04:37:00 -0700, christian.bau wrote:
>>>>>> There is no way in conforming Standard C to access the representation
>>>>>> of a float through type int, unsigned int, long or long int, even
>>>>>> though this would be very useful.
>>>>> float f;
>>>>> int i;
>>>>> memcpy(&i, &f, sizeof f);
>>>>> /* do what you want with i */
>>>>> memcpy(&f, &i, sizeof f);
>>>>
>>>> I don't think this changes anything.
>>>
>>> It does. One problem with using *(int *) &f, simplified a bit, is that
>>> you're reading and modifying a float using an lvalue of type int. Using
>>> memcpy to move f's representation into a real int avoids this one.

>>
>> I don't think it does. If you think float and int variables are somehow
>> special, use malloced memory instead:

>
> The rules for dynamically allocated memory are different.


Where do you read that distinction?


>> You are accessing memory with the same content the same way. If the
>> sizeof (float) bytes pointed to by p1 are a float which cannot be
>> accessed as an integer after the assignment (*fp = 42.0), so are the
>> sizeof (float) bytes pointed to by p2 after the first memcpy.

>
> Correct, but this isn't about "a float which cannot be accessed as an
> integer". It is already stated as an implementation detail that a float
> _can_ be accessed as an integer.


"cannot be accessed without causing undefined behaviour". I assumed that
the context was clear.

hp


--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | http://www.velocityreviews.com/forums/(E-Mail Removed) |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
 
Reply With Quote
 
 
 
 
Thad Smith
Guest
Posts: n/a
 
      09-09-2007
christian.bau wrote:

> There is no way in conforming Standard C to access the representation
> of a float through type int, unsigned int, long or long int, even
> though this would be very useful.


Agreed.

> There is not even a method that
> works in practice on a reasonable range of existing compilers that are
> in common use. On some compilers access through a pointer of the
> integer type will "work", on others using a union "works". It is
> tricky, it depends on the level of compiler optimisation, it depends
> on the exact circumstances, and it is just hard to get right.


I disagree here. In my experience, most processors utilize all bits of
an unsigned int as value bits, allowing a union of float and a
suitable-selected unsigned int to access all the bits within a float.
Of course the significance of the bits is dependent on the particular
system.

Your experience may be different. On what systems does compiler
optimization affect the access of float representation through a union
with unsigned int?

--
Thad
 
Reply With Quote
 
Harald van =?UTF-8?B?RMSzaw==?=
Guest
Posts: n/a
 
      09-10-2007
Peter J. Holzer wrote:
> On 2007-09-09 16:13, Harald van Dijk <(E-Mail Removed)> wrote:
>> Peter J. Holzer wrote:
>>> On 2007-09-09 12:56, Harald van Dijk <(E-Mail Removed)> wrote:
>>>> Peter J. Holzer wrote:
>>>>> On 2007-09-09 11:51, Army1987 <(E-Mail Removed)> wrote:
>>>>>> On Sun, 09 Sep 2007 04:37:00 -0700, christian.bau wrote:
>>>>>>> There is no way in conforming Standard C to access the
>>>>>>> representation of a float through type int, unsigned int, long or
>>>>>>> long int, even though this would be very useful.
>>>>>> float f;
>>>>>> int i;
>>>>>> memcpy(&i, &f, sizeof f);
>>>>>> /* do what you want with i */
>>>>>> memcpy(&f, &i, sizeof f);
>>>>>
>>>>> I don't think this changes anything.
>>>>
>>>> It does. One problem with using *(int *) &f, simplified a bit, is that
>>>> you're reading and modifying a float using an lvalue of type int. Using
>>>> memcpy to move f's representation into a real int avoids this one.
>>>
>>> I don't think it does. If you think float and int variables are somehow
>>> special, use malloced memory instead:

>>
>> The rules for dynamically allocated memory are different.

>
> Where do you read that distinction?


C99 6.5p6:
"The effective type of an object for an access to its stored value is the
declared type of the object, if any. 72) [...]
72) Allocated objects have no declared type."

The effective type is further explained in the rest of that and the
following paragraph.

>>> You are accessing memory with the same content the same way. If the
>>> sizeof (float) bytes pointed to by p1 are a float which cannot be
>>> accessed as an integer after the assignment (*fp = 42.0), so are the
>>> sizeof (float) bytes pointed to by p2 after the first memcpy.

>>
>> Correct, but this isn't about "a float which cannot be accessed as an
>> integer". It is already stated as an implementation detail that a float
>> _can_ be accessed as an integer.

>
> "cannot be accessed without causing undefined behaviour". I assumed that
> the context was clear.


It wasn't to me, but it is now. Thanks for the clarification.
 
Reply With Quote
 
Bart van Ingen Schenau
Guest
Posts: n/a
 
      09-10-2007
Peter J. Holzer wrote:

> I don't think it does. If you think float and int variables are
> somehow special, use malloced memory instead:
>
> void *p1, *p2;
> float *fp;
> int *ip;
>
> assert(sizeof (int) == sizeof (float));
> p1 = malloc(sizeof (float));
> p2 = malloc(sizeof (int));
> fp = p1;
> ip = p2;
> *fp = 42.0;
> memcpy(p2, p1, sizeof (float));
> /* do something with *ip */
> memcpy(p1, p2, sizeof (float));


Here, the compiler must copy the representation of *fp into *ip (and
later back again).
Any meddling you do to *ip in between should be reflected back in *fp
after the copy back.

>
> How is this different from
>
> p1 = malloc(sizeof (float));
> fp = p1;
> ip = p1;
> *fp = 42.0;
> /* do something with *ip */


Due to the aliasing rules, the compiler may assume (and some DO assume)
that any changes made to *ip will not affect *fp, because they are
pointers to unrelated types and therefor can't be aliases.

The fact that ip and fp point to the same block of memory simply means
that you invoked UB by breaking the aliasing rules.

> ?
>
> hp
>

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://www.eskimo.com/~scs/C-faq/top.html
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
 
Reply With Quote
 
Chris Torek
Guest
Posts: n/a
 
      09-15-2007
In article <46e46369$0$79259$(E-Mail Removed) s.com>
Thad Smith <(E-Mail Removed)> wrote:
>... In my experience, most processors utilize all bits of
>an unsigned int as value bits, allowing a union of float and a
>suitable-selected unsigned int to access all the bits within a float.
>Of course the significance of the bits is dependent on the particular
>system.
>
>Your experience may be different. On what systems does compiler
>optimization affect the access of float representation through a union
>with unsigned int?


GCC on x86, for one. The particular case here was a union of
"double" with an array of two 32-bit integers, rather than "float"
with a single 32-bit integer, but the problem was that the compiler's
alias analysis made the assumption that fiddling with the integer
portion of the union left the double portion unchanged, so that an
attempt to build an infinity and/or adjust an exponent (I have
forgotten some of the details) failed.

We got around the problem with a rather heavy-handed application
of "volatile" (not my preferred solution, but it worked, and I was
overruled on "really fixing" the code). In addition to that, some
GCC-internals people claimed that this was a bug in GCC and would
be fixed at some point.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
 
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
typeof x == 'undefined' or x == undefined? -Lost Javascript 13 01-31-2007 12:04 AM
undefined vs. undefined (was: new Array() vs []) VK Javascript 45 09-12-2006 05:26 PM
xslt queries in xml to SQL queries Ian Roddis Python 3 02-26-2006 06:49 PM
so many queries within queries I'm confused Abby Lee ASP General 11 08-06-2004 07:56 PM
undefined behavior or not undefined behavior? That is the question Mantorok Redgormor C Programming 70 02-17-2004 02:46 PM



Advertisments