Reputation: 1654
I met a behaviour I don't understand. I want fun to return a 2 byte val. I create a 4 byte var to do some processing and return the variable. My assumption is the variable is implicitly converted to short. However, it appears that the returned value isnt rly 2 byte, because the printf fun prints a value greater than 2^16 unless I place (short) before fun(). Why is that?
short fun()
{
long var = 2<<20;
return var;
}
printf("%i", fun());
Upvotes: 0
Views: 97
Reputation: 222272
In return var;
, the value of var
is converted to the return type of the function, which is short
. Since the value is outside the range of short
in your C implementation, there is an overflow. The C specification does not define what happens when there is integer overflow.
In spite of this, the behavior is a little odd. In the printf
call, many C implementations would use only 16 bits from fun()
, promote them to an int
, and pass them to printf
. Thus, the output would be “0” in spite of the overflow.
What may be happening in your case is that the compiler implements the conversion to short
by simply ignoring it and leaving the value in the processor register where it was held for var
(and uses the same register to return the function value). This is permitted by the C standard because, if the long
value in the register were in the short
domain, leaving the bits unchanged produces the same value when interpreted as a short
. If the long
value is outside the short
domain, it does not matter what happens, because the C standard does not define what must happen.
Then the contents of the register are simply passed directly to printf
as an argument. Again, this is valid because it produces the right result if the value is in the short
domain and anything is permitted if the var
value were not in the short
domain.
Upvotes: 1
Reputation: 7802
you start with 10
and left shift 20 to 1000000000000000000000
which exceeds the range of short and passes it to a function that gets a variadic argument (...)
when printf (and other variadic function) look at the value it is basically just a memory location and it uses the format specifier to cast it back to the original type. Here is a macro example of what it is basically doing:
#define va_arg(ap,type) (*(type *)(((ap)+=(((sizeof(type))+(sizeof(int)-1)) \
& (~(sizeof(int)-1))))-(((sizeof(type))+ \
(sizeof(int)-1)) & (~(sizeof(int)-1)))))
If you added a format specifier that cast it to short, it could see the casted short. Aside from that just keep (short)-ing your fun().
Upvotes: 1
Reputation: 400146
Variadic functions such as printf
perform what are called the default argument promotions on their operands. In particular, integers narrower than int
(such as short
) automatically get widened to int
when they are passed into variadic functions.
One way to get around this is to use the h
length modifier which says "even though you're dealing with an int
value, pretend that it's really a short
". Then, printf
will narrow the value back to short
before formatting the output. For example:
printf("%hi", fun());
Upvotes: 3