By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
460,028 Members | 1,026 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 460,028 IT Pros & Developers. It's quick & easy.

Undefined behavior - 2 queries

P: n/a
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)) {
/* 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.

2) I've seen code like the following:

struct s {
int a;
char *b;
float c;
} s;
int *i = (int *) s;

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

Cheers!

Sep 8 '07 #1
Share this Question
Share on Google+
20 Replies


P: n/a
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 != ?
/* 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.
The behaviour is outside the scope of the C standard, and very likely also
not defined as an extension by your particular implementation. If you want
your code to be portable, don't do it. If you don't need your code to be
portable, try to figure out how to do it using the extensions your compiler
provides. It's possible you actually do have a compiler that officially
allows your current code as an extension, but I doubt it.
2) I've seen code like the following:

struct s {
int a;
char *b;
float c;
} s;
int *i = (int *) s;

Isn't this undefined?
This is not allowed. You can't convert a structure to a pointer. If you
meant (int *) &s, then it's valid, though I personally prefer to write
&s.a.
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.
Sep 8 '07 #2

P: n/a

"Tommy Vercetti" <no@spam.comwrote in message
news:sl********************@nospam.invalid...
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)) {
/* 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.

2) I've seen code like the following:

struct s {
int a;
char *b;
float c;
} s;
int *i = (int *) s;

Isn't this undefined? Won't this blow up if the compiler inserts padding
before the first element of the struct?
The first example should read if(sizeof(float) != sizeof(int)). If this is
false, the code is almost correct. However the float could contain a legal
float which is a trap value for an integer. You'd have to be on a pretty
pathological platform for this to be a problem, but a conforming
implementation could crash you out.

The second example is OK. The first element of a struct has the same address
as the whole. No prepadding is allowed, though padding may be inserted at
the end or between elements.

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

Sep 9 '07 #3

P: n/a
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 - at the machine code level, most processors will
have a single instruction for &.
> /* 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.

The behaviour is outside the scope of the C standard, and very likely also
not defined as an extension by your particular implementation. If you want
your code to be portable, don't do it. If you don't need your code to be
portable, try to figure out how to do it using the extensions your compiler
provides. It's possible you actually do have a compiler that officially
allows your current code as an extension, but I doubt it.
Even though the undefined-behavior lines aren't called in situations
where they'd be undefined? E.g. in the following code:

if(1==2) {
char *p=NULL;
*p; /* KABOOM! */
}

can you really call this UB when the line invoking UB is guaranteed
never to be called?
>
>2) I've seen code like the following:

struct s {
int a;
char *b;
float c;
} s;
int *i = (int *) s;

Isn't this undefined?

This is not allowed. You can't convert a structure to a pointer. If you
meant (int *) &s, then it's valid, though I personally prefer to write
&s.a.
Yes, that was a typo.
>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!

Sep 9 '07 #4

P: n/a
"Malcolm McLean" <re*******@btinternet.comwrites:
"Tommy Vercetti" <no@spam.comwrote in message
news:sl********************@nospam.invalid...
[...]
>1) Is the following code undefined?

float myfunction(float f)
{
if(sizeof(float) & sizeof(int)) {
/* 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.
[...]
>
The first example should read if(sizeof(float) != sizeof(int)). If
this is false, the code is almost correct. However the float could
contain a legal float which is a trap value for an integer. You'd have
to be on a pretty pathological platform for this to be a problem, but
a conforming implementation could crash you out.
[...]

It could also fail if int and float have different alignment
requirements.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 9 '07 #5

P: n/a
"Tommy Vercetti" <no@spam.comwrote in message
news:sl********************@nospam.invalid...
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 - at the machine code level, most processors will
have a single instruction for &.
>> /* 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.

The behaviour is outside the scope of the C standard, and very likely
also
not defined as an extension by your particular implementation. If you
want
your code to be portable, don't do it. If you don't need your code to be
portable, try to figure out how to do it using the extensions your
compiler
provides. It's possible you actually do have a compiler that officially
allows your current code as an extension, but I doubt it.

Even though the undefined-behavior lines aren't called in situations
where they'd be undefined? E.g. in the following code:

if(1==2) {
char *p=NULL;
*p; /* KABOOM! */
}

can you really call this UB when the line invoking UB is guaranteed
never to be called?
>>
>>2) I've seen code like the following:

struct s {
int a;
char *b;
float c;
} s;
int *i = (int *) s;

Isn't this undefined?

This is not allowed. You can't convert a structure to a pointer. If you
meant (int *) &s, then it's valid, though I personally prefer to write
&s.a.

Yes, that was a typo.
>>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's not.
If you think about it, inserting a padding byte before the first member
won't solve the problem of alignment.

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

Sep 9 '07 #6

P: n/a
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.
>
>> /* 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.

The behaviour is outside the scope of the C standard, and very likely also
not defined as an extension by your particular implementation. If you want
your code to be portable, don't do it. If you don't need your code to be
portable, try to figure out how to do it using the extensions your compiler
provides. It's possible you actually do have a compiler that officially
allows your current code as an extension, but I doubt it.

Even though the undefined-behavior lines aren't called in situations
where they'd be undefined? E.g. in the following code:

if(1==2) {
char *p=NULL;
*p; /* KABOOM! */
}

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.
>>2) I've seen code like the following:

struct s {
int a;
char *b;
float c;
} s;
int *i = (int *) s;

Isn't this undefined?
[snip]
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!
The standard explicitly require that a pointer to a struct can point to
its first member if converted to its type.

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

Sep 9 '07 #7

P: n/a
Tommy Vercetti 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 - at the machine code level, most processors will
have a single instruction for &.
And most processors will also have a single instruction for !=. This is
irrelevant though, since sizeof(float) and sizeof(int) are constants, and
the compiler is required to be able to evaluate the expression at compile
time. It would take a particularly perverse compiler to not actually do so.
Sep 9 '07 #8

P: n/a
On 2007-09-09 08:10, Tommy Vercetti <no@spam.comwrote:
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 & 8) == 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.
| | | hj*@hjp.at |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
Sep 9 '07 #9

P: n/a
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

Sep 9 '07 #10

P: n/a
On Sep 9, 9:10 am, Tommy Vercetti <n...@spam.comwrote:
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.
Sep 9 '07 #11

P: n/a
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

Sep 9 '07 #12

P: n/a
On 2007-09-09 11:51, Army1987 <ar******@NOSPAM.itwrote:
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.
| | | hj*@hjp.at |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
Sep 9 '07 #13

P: n/a
On Sun, 09 Sep 2007 14:19:12 +0200, Peter J. Holzer wrote:
On 2007-09-09 11:51, Army1987 <ar******@NOSPAM.itwrote:
>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

Sep 9 '07 #14

P: n/a
Peter J. Holzer wrote:
On 2007-09-09 11:51, Army1987 <ar******@NOSPAM.itwrote:
>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.
Sep 9 '07 #15

P: n/a
On 2007-09-09 12:56, Harald van Dijk <tr*****@gmail.comwrote:
Peter J. Holzer wrote:
>On 2007-09-09 11:51, Army1987 <ar******@NOSPAM.itwrote:
>>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.
| | | hj*@hjp.at |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
Sep 9 '07 #16

P: n/a
Peter J. Holzer wrote:
On 2007-09-09 12:56, Harald van Dijk <tr*****@gmail.comwrote:
>Peter J. Holzer wrote:
>>On 2007-09-09 11:51, Army1987 <ar******@NOSPAM.itwrote:
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.
Sep 9 '07 #17

P: n/a
On 2007-09-09 16:13, Harald van Dijk <tr*****@gmail.comwrote:
Peter J. Holzer wrote:
>On 2007-09-09 12:56, Harald van Dijk <tr*****@gmail.comwrote:
>>Peter J. Holzer wrote:
On 2007-09-09 11:51, Army1987 <ar******@NOSPAM.itwrote:
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.
| | | hj*@hjp.at |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
Sep 9 '07 #18

P: n/a
Peter J. Holzer wrote:
On 2007-09-09 16:13, Harald van Dijk <tr*****@gmail.comwrote:
>Peter J. Holzer wrote:
>>On 2007-09-09 12:56, Harald van Dijk <tr*****@gmail.comwrote:
Peter J. Holzer wrote:
On 2007-09-09 11:51, Army1987 <ar******@NOSPAM.itwrote:
>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.
Sep 10 '07 #19

P: n/a
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/
Sep 10 '07 #20

P: n/a
In article <46***********************@auth.newsreader.octanew s.com>
Thad Smith <Th*******@acm.orgwrote:
>... 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.
Sep 15 '07 #21

This discussion thread is closed

Replies have been disabled for this discussion.