# Behavior of the code

Discussion in 'C Programming' started by somenath, Dec 25, 2007.

1. ### somenathGuest

Hi All,

I was going through one of the exercise of one C tutorial .
In that they have given one small code and asked about the output.

#include <stdio.h>
int main(void)
{
int x = 0xFFFFFFF0;
signed char y;
y = x;
printf("%x\n", y);
return 0;
}
Output of the program is

fffffff0

The explanation they have given as bellow

Since %x is being used for printing, the printf statement will promote
y to an integer and hence fffffff0 will be printed.

I have doubt about the explanation.

My understanding is
1) if we assign a signed variable more than its max size it will
overflow so the behavior is undefined .
2) And in the explanation it says %x promote y to an integer but I
think it converts its argument to hexadecimal.
Is my understanding wrong?

Regards,
Somenath

somenath, Dec 25, 2007

2. ### Thomas LumleyGuest

Good. The explanation is wrong.

It's not quite as bad as that. If 0xfffffff0 is interpreted as an int
and ints have a 32-bit two's complement representation then x is -16,
which is within the range of signed char. For other implementation
choices, such as 64-bit ints, there may be undefined behaviour for
exactly the reason you suggest.

There is some implementation-dependence here: obviously the size of
int,
but also (if I am interpreting the standard correctly), whether
0xfffffff0
is interpreted as an int or unsigned int constant. If it is
interpreted
as unsigned int then I think you do have undefined behaviour

Yes. You are right, the explanation is wrong. We can look at a
simplified version of the program that doesn't have the confusing
conversion from int.

#include <stdio.h>
int main(void)
{
signed char y = -16;
printf("%x\n", y);
return 0;
}

The actual output is implementation-specified, but on my computer
this
also prints
fffffff0

In this program, since y is part of the variable-length argument
list of printf() it will be promoted[1] by the default argument
promotions to int. printf() receives an int value of -16, and the
%x format asks for this in hexadecimal. The %x format has nothing to
do with the promotion of y to int.

-thomas

[1] I'm not sure whether it is possible for signed char to have values
that don't fit in an int. I'm sure that someone on the list is.

Thomas Lumley, Dec 25, 2007

3. ### santoshGuest

The C standard explicitly excuses such restrictions. int neither needs
to be 32 bits nor be represented in twos-complement form. It needs to
hold values in the range -32767 to 32767. It could be twos-complement,
ones-complement or sign-and-magnitude or something else. It is not
explicitly stated but we may presume at least 16 value bits for an int,
as C needs binary representation.

santosh, Dec 25, 2007
4. ### Old WolfGuest

This is rubbish, your tutorial is lame
It is implementation-defined to assign an out-of-range
value to an int. Your compiler documentation should say
somewhere what it does in this case.

It looks like on your implmentation, the result is that
-16 gets assigned to the int.
The behaviour is undefined because you have to explicitly
pass an unsigned int for %x , the compiler doesn't do any
conversions.

Old Wolf, Dec 25, 2007
5. ### somenathGuest

To get little bit clearer .
So if i assigned 128 to signed char it is not guranted that it will
be converted to -128
For example
signed char x = 0x80;
x will not always contains -128 ?
Is it only possible in case of 2's complement representation ?

somenath, Dec 25, 2007
6. ### Malcolm McLeanGuest

Yes. It practise it is most unlikely that you will ever encounter a
non-two's complement machine, but C allows it.
However it is not so unlikely that a char will be more than 8 bits. Not all
machines do 8-bit addressing at an instruction level, in which case it is
reasonable to make char more bits.

Malcolm McLean, Dec 25, 2007
7. ### somenathGuest

I am unable to understand the conversation
Let me explain my understanding .

int x = 0xFFFFFFF0;
signed char y;
y = x;

In these three statements y is guaranteed to contain the last byte of
the integer. As my machine is Little endian y wil be equal to F0 i.e
240 in decimal.
Now when I print using %x it should print the hexadecimal
representation of 240 i.e F0 .Why it is printing fffffff0 ?

somenath, Dec 25, 2007
8. ### santoshGuest

This is not guaranteed for plain signed char. You could test for the
presence of int8_t and use that if available, but it's likely not to be
available on a non-twos-complement machine, in which case you'll have
to use a wider type.

But except for some weird architectures, you needn't worry about the
non-availability of twos-complement.

santosh, Dec 25, 2007
9. ### santoshGuest

somenath wrote:

No it's not. How can it be when 'x' isn't guaranteed to hold 0xfffffff
in the first place. Use a smaller value like 0x7fff.
Because of format specifier mismatch. You are supplying a char and
telling it to look for an int. As a result, printf accesses more bytes
than it should and prints whatever happens to be in the extra bytes.
Use the 'hhx' format specifier and try again. Also use a cast for the
assignment to 'y'.

santosh, Dec 25, 2007
10. ### Harald van DÄ³kGuest

If CHAR_BIT == 8, then char is an integer type with a width of 8 bits,
and when such an integer type existed, the (u)int8_t typedefs would have
to be provided. This requirement was obviously useless, and an attempt

"These types are optional. However, if an implementation provides integer
types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for
the signed types) that have a two's complement representation, it shall
define the corresponding typedef names."

"These types are optional. However, if an implementation provides integer
types with widths of 8, 16, 32, or 64 bits, it shall define the
corresponding typedef names."

-- but, if CHAR_BIT == 8, unsigned char is still an unsigned integer type
with a width of 8 bits and no padding, meaning uint8_t is required to be
provided. And when uint8_t is provided, int8_t is required as well.

In other words, while you're quite possibly correct about the intent,
what the standard actually says is significantly different.

Harald van DÄ³k, Dec 25, 2007
11. ### somenathGuest

I have changed the code as below

#include <stdio.h>
int main(void)
{
int x = 0x7fff;
signed char y;
y =(signed char) x;
printf("%hhx\n", y);
return 0;

}
Now is it guaranteed that y will hold ff which is the last byte of x ?

Now the output is ffffffff
Why it is not ff only ?

somenath, Dec 25, 2007
12. ### Harald van DÄ³kGuest

Why? There is an implicit conversion from int to signed char, which
behaves exactly the same as an explicit conversion from int to signed
char.

Harald van DÄ³k, Dec 25, 2007
13. ### santoshGuest

I get 'ff' here. What compiler are you using and what are the options
that you are passing it?

santosh, Dec 25, 2007
14. ### jacob naviaGuest

I get ff here too

jacob navia, Dec 25, 2007
15. ### jacob naviaGuest

gcc produces ff
lcc-win produces ff
msvc (2005) produces ffff

jacob navia, Dec 25, 2007
16. ### Joe WrightGuest

I took the liberty of changing the code again..

#include <stdio.h>
int main(void)
{
int x = 0x7fff;
char y;
y = x;
printf("%hx\n", y);
return 0;
}
None of the casting was necessary and "%hhx" is weird. This prints ffff
just as I expect it to. What is the case for ff?

Joe Wright, Dec 25, 2007
17. ### jacob naviaGuest

See my other reply. I think Microsoft has a bug here

jacob navia, Dec 25, 2007

The compiler DOES convert from signed char to int, but the end result is
undefined because the result of interpreting an int with negative value as
an unsigned int is undefined.

19. ### Joe WrightGuest

My compiler is gcc (djgpp) and I get ffff. If msvc gets ffff too I don't
see the 'bug' you suggest. Once x is assigned to y the value of y is -1.
In the printf the value of y is promoted to int (still -1) and displayed
as unsigned short (ffff). In order to print ff the value of y must be
255 and there is no case for that here. Could be lcc-win is broke.

Joe Wright, Dec 25, 2007
20. ### jacob naviaGuest

I was speaking about the second version, and did not see that you
have changed it AGAIN. After that change I get ffff again.

The bug I was referring to was for this code
#include <stdio.h
int main(void)
{
int x = 0x7fff;
signed char y;
y =(signed char) x;
printf("%hhx\n", y);
return 0;

}

jacob navia, Dec 25, 2007