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

Does casting lvalue lead to Undefined Behaviour ?

P: n/a
Please see the code below

-- start listing is_it_ub.c --

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

int main (void)
{
unsigned char buff[20];
unsigned int i;

i = 0xaabbccddUL;
*((int *)buff) = i; /* Is this UB ? */

printf("buff: %x:%x:%x:%x\n", buff[0], buff[1], buff[2], buff[3]);

return EXIT_SUCCESS;
}

-- end listing --

Output:
buff: dd:cc:bb:aa

Output seems correct on my Little Endian PC.

In the statement: "*((int *)buff) = i; ", buff is casted to be treated
as an int *. Is this valid?

My compiler does not produce any diagnostics for the above
program but somebody else complained that their compiler
warns "casting of lvalue is deprecated".

Thanks.

Dec 29 '06 #1
Share this Question
Share on Google+
5 Replies


P: n/a
p_***********@yahoo.co.in wrote:
Please see the code below

-- start listing is_it_ub.c --

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

int main (void)
{
unsigned char buff[20];
unsigned int i;

i = 0xaabbccddUL;
*((int *)buff) = i; /* Is this UB ? */
Yes. There is no guarantee that buff is correctly aligned for an int.
You can either use memcpy(), or access the representation via (unsigned
char *) &i.

In theory, it's also possible that sizeof(int) is greater than 20,
which will cause obvious problems, but that's not likely to happen in
practice.
printf("buff: %x:%x:%x:%x\n", buff[0], buff[1], buff[2], buff[3]);
This assumes that an int is four bytes. This is not necessarily true,
and in this case the problem does occur in practice.
return EXIT_SUCCESS;
}

-- end listing --

Output:
buff: dd:cc:bb:aa

Output seems correct on my Little Endian PC.

In the statement: "*((int *)buff) = i; ", buff is casted to be treated
as an int *. Is this valid?

My compiler does not produce any diagnostics for the above
program but somebody else complained that their compiler
warns "casting of lvalue is deprecated".
That warning refers to an implementation-specific extension which
you're not using, so don't worry about that.

Dec 29 '06 #2

P: n/a
p_***********@yahoo.co.in said:
Please see the code below

-- start listing is_it_ub.c --

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

int main (void)
{
unsigned char buff[20];
unsigned int i;

i = 0xaabbccddUL;
*((int *)buff) = i; /* Is this UB ? */
Yes. You're evaluating buff (which is a pointer to char), and then
converting that value to a pointer to int, but there is no guarantee that
it will be properly aligned. You then dereference the possibly-invalid
pointer thus obtained. On systems where this works, it's harmless. On
systems where it doesn't, we're talking potential bus errors, which are
definite showstoppers.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 29 '06 #3

P: n/a
In article <11**********************@a3g2000cwd.googlegroups. com>,
<p_***********@yahoo.co.inwrote:
unsigned char buff[20];
unsigned int i;
i = 0xaabbccddUL;
*((int *)buff) = i; /* Is this UB ? */
Yes, because you don't know that buff has been properly aligned
to write an int into the beginning of it.

Also, you are assuming that unsigned int is big enough to hold
something 32 bits wide; an unsigned int need only be 16 bits wide to
satisify the value constraints.

Your constant is written as an unsigned long and that is assigned
into the unsigned int. That's odd enough to stand out, but it should
not be a problem in practice: if unsigned long is wider than
unsigned int, the unsigned long will not have any sign extension,
and even if it did, that sign extension would effectively be removed
when assigned into the unsigned int.

Your assignment involves type punning on a plain int rather than
an unsigned int. There is the possibility that an arbitrary
unsigned int might become a trap representation when the same
bit pattern is used as an int; such problems become more -likely-
when the unsigned int has bits set that correspond to sign bits
in the int. The particular value you chose, 0xaabbccdd, is -likely-
to overlay the top bit of 0xaa or 0xcc onto the sign bit, so you -could-
be getting into trouble that way. Safer to convert through
unsigned int * .
--
I was very young in those days, but I was also rather dim.
-- Christopher Priest
Dec 29 '06 #4

P: n/a
Walter Roberson wrote:
In article <11**********************@a3g2000cwd.googlegroups. com>,
<p_***********@yahoo.co.inwrote:
unsigned char buff[20];
unsigned int i;
i = 0xaabbccddUL;
*((int *)buff) = i; /* Is this UB ? */
[...]
Your assignment involves type punning on a plain int rather than
an unsigned int. There is the possibility that an arbitrary
unsigned int might become a trap representation when the same
bit pattern is used as an int; such problems become more -likely-
when the unsigned int has bits set that correspond to sign bits
in the int. The particular value you chose, 0xaabbccdd, is -likely-
to overlay the top bit of 0xaa or 0xcc onto the sign bit, so you -could-
be getting into trouble that way. Safer to convert through
unsigned int * .
There is no possibility for a trap representation. The value is
converted to, not reinterpreted as, a signed int, which results in an
implementation-defined value (and a trap representation, by definition,
is not a value), or the raising of an implementation-defined signal. In
the former case, there's no UB. In the latter case, there is UB if the
signal is not handled, but even then, there is no trap representation.

That said, since padding bits aren't an issue (you know the
representation is a valid unsigned int), the only trap representations
a signed integer can have are all bits one, and all bits zero except
for the sign bit. Neither is possible here.

Dec 29 '06 #5

P: n/a
Harald van Dijk wrote:
Walter Roberson wrote:
In article <11**********************@a3g2000cwd.googlegroups. com>,
<p_***********@yahoo.co.inwrote:
unsigned char buff[20];
unsigned int i;
i = 0xaabbccddUL;
*((int *)buff) = i; /* Is this UB ? */
[...]
Your assignment involves type punning on a plain int rather than
an unsigned int. There is the possibility that an arbitrary
unsigned int might become a trap representation when the same
bit pattern is used as an int; such problems become more -likely-
when the unsigned int has bits set that correspond to sign bits
in the int. The particular value you chose, 0xaabbccdd, is -likely-
to overlay the top bit of 0xaa or 0xcc onto the sign bit, so you -could-
be getting into trouble that way. Safer to convert through
unsigned int * .

There is no possibility for a trap representation. The value is
converted to, not reinterpreted as, a signed int, which results in an
implementation-defined value (and a trap representation, by definition,
is not a value), or the raising of an implementation-defined signal. In
the former case, there's no UB. In the latter case, there is UB if the
signal is not handled, but even then, there is no trap representation.
Correction: the wording actually only says the result is
implementation-defined, not that the result is an
implementation-defined value. However, this is no licence for
implementations to declare the result is undefined (as it would be in
the case of a trap representation).
That said, since padding bits aren't an issue (you know the
representation is a valid unsigned int), the only trap representations
a signed integer can have are all bits one, and all bits zero except
for the sign bit. Neither is possible here.
Dec 29 '06 #6

This discussion thread is closed

Replies have been disabled for this discussion.