Velocity Reviews - Computer Hardware Reviews

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

Reply
Thread Tools

Undefined behavior - 2 queries

 
 
Peter J. Holzer
Guest
Posts: n/a
 
      09-09-2007
On 2007-09-09 08:10, Tommy Vercetti <(E-Mail Removed)> wrote:
> On 8 Sep 2007 at 22:45, Harald van Dijk wrote:
>> Tommy Vercetti wrote:
>>> Hi -
>>>
>>> Great group!
>>>
>>> I have 2 queries about undefined behavior:
>>>
>>> 1) Is the following code undefined?
>>>
>>> float myfunction(float f)
>>> {
>>> if(sizeof(float) & sizeof(int)) {

>>
>> I've tried figuring out why you would use the & operator here. I'm not
>> seeing it. Did you mean to use != ?

>
> It's an optimization -


No, it's simply wrong.

Consider the (common) case of sizeof(float) == sizeof(int) == 4:
4 & 4 == 4, so the then branch (slow ordinary FP operations) is
executed. This is almost certainly not what you wanted.

If sizeof(int) == 8 and sizeof(float) == 4, (4 & == 0, so the else
branch (int i = *(int *)&f) is executed, which causes undefined
behaviour due to the possible alignment mismatch.

But you haven't just reversed the test: If for example sizeof(int) == 8
and sizeof(float) == 12, then it will still test as true.


> at the machine code level, most processors will
> have a single instruction for &.


At the machine code level, most processors also have single instructions
for comparing integers. But most likely, the test will never be made at
runtime because it can already be evaluated at compile time.

Morals: Write what you mean and let the compiler worry about
optimization.

>
>>> /* use slow ordinary FP operations */
>>> } else {
>>> int i = *(int *)&f;
>>> /* do clever bit-twiddling floating-point operation */
>>> }
>>> }
>>>
>>> It only attempts to access the float as an integer when this makes
>>> sense.


Actually, it only attempts to access the float as an integer when this
makes no sense. But assuming you got the test right: I think this is
still undefined behaviour:

1) Even if the size is the same, the alignment can be different (think
of the old x86 series, where integer and fp unit were separate
processors: They could easily have had different alignment
requirements).

2) Even if the alignment is the same, reinterpreting an fp number as an
int is not defined. The bit pattern can represent a trap value, for
example.

And thirdly, knowing the size is not enough for "clever bit-twiddling".
You need to know the representation. So that code should be something
like:


#if __STDC_IEC_559__ && CLEVER_BIT_TWIDDLING_IS_FASTER
/* clever bit twiddling here */
#else
/* normal FP here
#endif


> Even though the undefined-behavior lines aren't called in situations
> where they'd be undefined?


No, but in your code the undefined-behavior will be called. Your checks
to prevent that are insufficient.

> E.g. in the following code:
>
> if(1==2) {
> char *p=NULL;
> *p; /* KABOOM! */
> }


That's ok.


>>> Won't this blow up if the compiler inserts padding
>>> before the first element of the struct?

>>
>> Right. Which is not a problem, since the compiler is not allowed to insert
>> padding before the first element of the struct.

>
> I think if you check, the compiler is allowed to insert padding into
> structs as it sees fit. In particular, if the address of s isn't
> properly aligned for an int then it will have to insert padding!


No, it will have to ensure that s is properly aligned for all its
members.

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
 
 
 
 
CBFalconer
Guest
Posts: n/a
 
      09-09-2007
Tommy Vercetti wrote:
> Harald van Dijk wrote:
>> Tommy Vercetti wrote:
>>

.... snip ...
>>>
>>> struct s {
>>> int a;
>>> char *b;
>>> float c;
>>> } s;
>>> int *i = (int *) &s; /* & added - cbf */

>>

.... snip ...
>
>>> Won't this blow up if the compiler inserts padding
>>> before the first element of the struct?

>>
>> Right. Which is not a problem, since the compiler is not allowed
>> to insert padding before the first element of the struct.

>
> I think if you check, the compiler is allowed to insert padding into
> structs as it sees fit. In particular, if the address of s isn't
> properly aligned for an int then it will have to insert padding!


But not before the first item in a struct. The struct won't be
assigned any address that is not suitable for an int.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>



--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
 
 
 
Army1987
Guest
Posts: n/a
 
      09-09-2007
On Sun, 09 Sep 2007 10:43:35 +0200, Army1987 wrote:

> On Sun, 09 Sep 2007 10:10:00 +0200, Tommy Vercetti wrote:
>
>> On 8 Sep 2007 at 22:45, Harald van Dijk wrote:
>>> Tommy Vercetti wrote:

> [snip]
>>>> float myfunction(float f)
>>>> {
>>>> if(sizeof(float) & sizeof(int)) {
>>>
>>> I've tried figuring out why you would use the & operator here. I'm not
>>> seeing it. Did you mean to use != ?

>>
>> It's an optimization - at the machine code level, most processors will
>> have a single instruction for &.

> & is bitwise and, it will be nonzero unless the operands have no
> set bits in common. Probably you mean ^ (bitwise xor), which is
> zero if and only if the operands are equal.

And anyway, the expression is a constant integer expression, so
it will be evaluated at compile time. And any decent compiler
will not generate any code for the branch which will not be
executed.
>>>> /* use slow ordinary FP operations */
>>>> } else {
>>>> int i = *(int *)&f;
>>>> /* do clever bit-twiddling floating-point operation */
>>>> }
>>>> }

[snip]
>> can you really call this UB when the line invoking UB is

guaranteed
>> never to be called?

> The situation is different. The fact that int and float have the same
> size doesn't require that they have the same alignment. For example,
> imagine that on a particular machine both floats and ints have 4 bytes,
> but floats can be placed anywhere, whereas ints must be aligned to word
> boundaries. Converting a float* to int* and dereferencing it causes UB
> if the float* points anywhere else than to the beginning of a 4-byte
> word.

Anyway, since the bit-twiddling is nonportable anyway (it depends
on the representation of floats), you can look up your
implementation's documentation to check that.

--
Army1987 (Replace "NOSPAM" with "email")
If you're sending e-mail from a Windows machine, turn off Microsoft's
stupid “Smart Quotes” feature. This is so you'll avoid sprinkling garbage
characters through your mail. -- Eric S. Raymond and Rick Moen

 
Reply With Quote
 
christian.bau
Guest
Posts: n/a
 
      09-09-2007
On Sep 9, 9:10 am, Tommy Vercetti <(E-Mail Removed)> wrote:

> >> if(sizeof(float) & sizeof(int)) {

>
> It's an optimization - at the machine code level, most processors will
> have a single instruction for &.


Considering that sizeof (float) and sizeof (int) are constants, this
argument is rather daft. On top of that, the code is wrong, because
sizeof(float) & sizeof(int) can only ever be zero if the sizes are
different, and in that case I'm sure you don't want to execute your
bit-fiddling code.

So you tried a nano-optimisation, didn't figure out that it would be
pointless as an optimisation, and on top of that you got it wrong.
Brilliant.


 
Reply With Quote
 
christian.bau
Guest
Posts: n/a
 
      09-09-2007
On Sep 9, 10:24 am, "Peter J. Holzer" <(E-Mail Removed)> wrote:

> Actually, it only attempts to access the float as an integer when this
> makes no sense. But assuming you got the test right: I think this is
> still undefined behaviour:
>
> 1) Even if the size is the same, the alignment can be different (think
> of the old x86 series, where integer and fp unit were separate
> processors: They could easily have had different alignment
> requirements).
>
> 2) Even if the alignment is the same, reinterpreting an fp number as an
> int is not defined. The bit pattern can represent a trap value, for
> example.


It is undefined behaviour anyway, because accessing an object of type
float using an lvalue of any type other than float or a character type
is _always_ undefined behaviour; that is just what the C Standard
says.

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. 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.

 
Reply With Quote
 
Army1987
Guest
Posts: n/a
 
      09-09-2007
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);
--
Army1987 (Replace "NOSPAM" with "email")
If you're sending e-mail from a Windows machine, turn off Microsoft's
stupid “Smart Quotes” feature. This is so you'll avoid sprinkling garbage
characters through your mail. -- Eric S. Raymond and Rick Moen

 
Reply With Quote
 
Peter J. Holzer
Guest
Posts: n/a
 
      09-09-2007
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.

hp


--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | (E-Mail Removed) |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
 
Reply With Quote
 
Army1987
Guest
Posts: n/a
 
      09-09-2007
On Sun, 09 Sep 2007 14:19:12 +0200, 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.


Of course this isn't portable, because you'd need to know the
representation of float, the endianness of int, etc., but (except
in the case of trap representations) it works, even if int and
float have different algnments, and even if a compiler optimizes
away either assignment in something like
union { float f; int i; } u;
u.f = 42.0;
u.i ^= MAGIC;
printf("%g\n", u.f);
--
Army1987 (Replace "NOSPAM" with "email")
If you're sending e-mail from a Windows machine, turn off Microsoft's
stupid “Smart Quotes” feature. This is so you'll avoid sprinkling garbage
characters through your mail. -- Eric S. Raymond and Rick Moen

 
Reply With Quote
 
Harald van =?UTF-8?B?RMSzaw==?=
Guest
Posts: n/a
 
      09-09-2007
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. The
other problems are all avoided already if the implementation makes
sizeof(float) equal to sizeof(int), and int has no trap representations.
 
Reply With Quote
 
Peter J. Holzer
Guest
Posts: n/a
 
      09-09-2007
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:


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));


How is this different from

p1 = malloc(sizeof (float));
fp = p1;
ip = p1;
*fp = 42.0;
/* do something with *ip */

?

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.

hp

--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | (E-Mail Removed) |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
 
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