Reputation: 109
Consider the following two C program. My question is in first program unsigned
keyword prints -12
but I think it should print 4294967284
but it does not print it for %d
specifier. It prints it for %u
specifier. But if we look on second program, the output is 144
where it should be -112
. Something is fishy about unsigned
keyword which I am not getting. Any help friends!
#include <stdio.h>
int main()
{ unsigned int i = -12;
printf(" i = %d\n",i);
printf(" i = %u\n",i);
return 0;
}
Above prorgam I got from this link : Assigning negative numbers to an unsigned int?
#include <stdio.h>
int main(void)
{unsigned char a=200, b=200, c;
c = a+b;
printf("result=%d\n",c);
return 0;
}
Upvotes: 3
Views: 407
Reputation: 263647
Each printf
format specifier requires an argument of some particular type. "%d"
requires an argument of type int
; "%u"
requires an argument of type unsigned int
. It is entirely your responsibility to pass arguments of the correct type.
unsigned int i = -12;
-12
is of type int
. The initialization implicitly converts that value from int
to unsigned int
. The converted value (which is positive and very large) is stored in i
. If int
and unsigned int
are 32 bits, the stored value will be 4294967284
(232-12).
printf(" i = %d\n",i);
i
is of type unsigned int
, but "%d"
requires an int
argument. The behavior is not defined by the C standard. Typically the value stored in i
will be interpreted as if it had been stored in an int
object. On most systems, the output will be i = -12
-- but you shouldn't depend on that.
printf(" i = %u\n",i);
This will correctly print the value of i
(assuming the undefined behavior of the previous statement didn't mess things up).
For ordinary functions, assuming you call them correctly, arguments will often be implicitly converted to the declared type of the parameter, if such a conversion is available. For a variadic function like printf
, which can take a varying number and type(s) of arguments, no such conversion can be done, because the compiler doesn't know what type is expected. Instead, arguments undergo the default argument promotions. An argument of a type narrow than int
is promoted to int
if int
can hold all values of the type, or to unsigned int
otherwise. An argument of type float
is promoted to double
(which is why "%f"
works for both float
and double
arguments).
The rules are such an argument of a narrow unsigned type will often (but not always) be promoted to (signed) int
.
unsigned char a=200, b=200, c;
Assuming 8-bit bytes, a
and b
are set to 200
.
c = a+b;
The sum 400
is too bit to fit in an unsigned char
. For unsigned arithmetic and conversion, out-of-range results are reduced to the range of the type. c
is set to 144
.
printf("result=%d\n",c);
The value of c
is promoted to int
; even though the argument is of an unsigned type, int
is big enough to hold all possible values of the type. The output is result=144
.
Upvotes: 12
Reputation: 141648
In the first program the behaviour is undefined. It's your responsibility to make sure that the format specifier matches the data type of the argument. The compiler emits code that assumes you got it right; at runtime it does not have to do any checks (and often, cannot do any checks even if it wanted to).
(For example, the library implementation printf function does not know what arguments you gave it , it only sees some bytes and it has to assume those are the bytes for the type that you specified using %d
).
You appear to be trying to infer something unsigned
means based on the output of a program with undefined behaviour. That won't work. Stick to well-defined programs (and preferably just read the definition of unsigned
).
In a comment you say:
could give me any reference of unsigned keyword. Still concept is not getting cleared to me. Unsigned definition in C/C++ standard.
In the C99 standard read section 6.2.5, from part 6 onwards.
The definition of unsigned int
is an integer type that can hold values from 0
up to a positive number UINT_MAX
(which should be one less than a power of two), which must be at least 65535
, and typically is 4294967295
.
When you write unsigned int i = -12;
, the compiler sees that -12
is outside of the range of permitted values for unsigned int
, and it performs a conversion. The definition of that conversion is to add or subtract UINT_MAX+1
until the value is in range.
The second part of your question is unrelated to all this. There are no unsigned int
in that program; only unsigned char
.
In that program, 200 + 200
gives 400
. As mentioned above, since this is out of range the compiler converts it by subtracting UCHAR_MAX+1
(i.e. 256) until it is in range. 400 - 256 = 144
.
Upvotes: 6
Reputation: 8033
The %d
and %u
specifiers of printf
have capability of (or, are responsible for) typecasting the input integer into int
and unsigned int
, respectively.
In fact printf
(in general, any variadic functions) and arithmetic operators can accept only three types of arguments (except for the format string): 4-byte int
, 8-byte long long
and double
(warning: very inaccurate description!) Any integral arguments whose size is less than int
are extended into int
. Any float arguments are extended into double
. These rules improve uniformity of the input parameters of printf
and arithmetic operators.
Regarding your 2nd example: the following steps take place
+
operator requires (unsigned
) char
operands to be extended into (unsigned
) int
values (which are 4-bytes integers in your case, I assume.)unsigned int
.unsigned char c
, so c
has the value of 400 % 256 == 144
.printf
requires all the smaller integral arguments to be expanded into int
, thus what printf
receives is 400 of a 4-bytes int
.%d
specifier prints the above argument as "400".Google for "default argument promotion" for more details.
Upvotes: -4