Reputation: 616
Consider the following program,
#include <stdio.h>
int main()
{
char a = 130;
unsigned char b = 130;
printf("a = %d\nb = %d\n",a,b);
return 0;
}
This program will show the following output.
a = -126
b = 130
My question is how printf()
function comes to know the type of a
is signed and type of b
is unsigned to show result like above?
Upvotes: 1
Views: 1458
Reputation: 128
printf()
does not know the data type of arguments. It works on format specifier you passed. The data type you are using is char
(having range from -128 to +127) and unsigned char
(having range from 0 to 255). Your output for a
is overflowed after 127. So the output comes to -126.
Upvotes: 1
Reputation: 778
The additional arguments to printf()
are formatted according to the type specifier. See here for a list of C format specifiers.
https://fr.cppreference.com/w/c/io/fprintf
It's true that one would not expect b
to be printed as 130
in your example since you used the %d
specifier and not %u
. This surprising behavior seems to be explained here.
Format specifier for unsigned char
I hope I got your question well.
Edit: I can not comment Felix Palmen's answer on account on my low reputation. default argument promotion indeed seems to be the key here, but to me the real question here besides the overflow of a
is why b
is still printed as 130
despite the use of the signed specifier. It can also be explained with default argument promotion but that should be made more precise.
Upvotes: 2
Reputation:
printf()
doesn't know the types, that's why you have to give a correct format string. The prototype for printf()
looks like this:
int printf(const char * restrict format, ...);
So, the only argument with a known type is the first one, the format string.
This also means that any argument passed after that is subject to default argument promotion -- strongly simplified, read it as any integer will be converted to at least int
-- or ask google about the term to learn each and every detail ;)
In your example, you have implementation defined behavior:
char a = 130;
If your char
could represent 130
, that's what you would see in the output of printf()
. Promoting the value to int
doesn't change the value. You're getting a negative number instead, which means 130
overflowed your char
. The result of overflowing a signed integer type during conversion in C is implementation defined, the value you're getting probably means that on you machine, char
has 8 bits (so the maximum value is 127
) and the signed integer overflow resulted in a wraparound to the negative value range. You can't rely on that behavior!
In short, the negative number is created in this line -- 130
is of type int
, assigning it to char
converts it and this conversion overflows.
Once your char
has the value -126
, passing it to printf()
just converts it to int
, not changing the value.
Upvotes: 5
Reputation: 4920
You need to have a look at the definition of printf
statement in stdio.h
. You already got the answer in comment printf
just write the string pointed by format to stdout.
It's variadic function and it use vargas to get all the arguments in variable-length argument list.
You This is from the glibc from the GNU version.
int __printf (const char *format, ...)
{
va_list arg;
int done;
va_start (arg, format);
done = vfprintf (stdout, format, arg);
va_end (arg);
return done;
}
What vfprintf does?
It just writes the string pointed by format to the stream, replacing any format specifier in the same way as printf does, but using the elements in the variable argument list identified by arg instead of additional function arguments.
More information about the vfprintf
Upvotes: 1