int a=65;
printf("%c", a);
I tried it on GCC on Ubuntu I don't know the version. But it worked and I wish to know how? Because according to me the size of char is smaller than int and hence it shouldn't have been possible.
int a=65;
printf("%c", a);
I tried it on GCC on Ubuntu I don't know the version. But it worked and I wish to know how? Because according to me the size of char is smaller than int and hence it shouldn't have been possible.
The printf
function has the following declaration:
int printf(const char *format, ...);
The first argument must be a pointer to a char
array, but any additional arguments can be of any type, so it's not a compiler error if a format specifier mismatches the parameter (although it is undefined behavior).
This still works however because of what %c
expects. From the man page:
If no l modifier is present, the int argument is converted to an unsigned char, and the resulting character is written. If an l modifier is present, the wint_t (wide character) argument is converted to a multibyte sequence by a call to the wcrtomb(3) function, with a conversion state starting in the initial state, and the resulting multibyte string is written.
From the above passage, %c
actually expects an int
and converts it to an unsigned char
for printing. So if that's the case why does passing an actual char
work? That is because of integer promotions. Any integer type smaller than int
is promoted to int
anyplace an int
can be used. Since printf
is variadic it can't check the types of its arguments, so a char
passed to printf
will get promoted to int
when the function is called.
7.21.6.1 The
...fprintf
function
8 The conversion specifiers and their meanings are:
...
c
If nol
length modifier is present, theint
argument is converted to anunsigned char
, and the resulting character is written. If anl
length modifier is present, thewint_t
argument is converted as if by an ls conversion specification with no precision and an argument that points to the initial element of a two-element array ofwchar_t
, the first element containing thewint_t
argument to thelc
conversion specification and the second a null wide character.
So, (f)printf
expects the argument corresponding to the %c
conversion specifier to have type int
, and will convert it to unsigned char
before formatting and displaying.
The value 65
can certainly fit in an unsigned char
(0-255), so there's no problem with the conversion there. If you pass an integer value outside that range, then I suspect the following comes into play:
6.3 Conversions
6.3.1.3 Signed and unsigned integers
...
2 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.60)
60) The rules describe arithmetic on the mathematical value, not the value of a given type of expression.
IOW, if you pass the value 321
, it should "wrap" around back to 65
('A'
in ASCII).
This is because of the default argument promotions. Anything smaller than int
, when passed as part of printf
's variable argument list, is converted to int
before the call. Therefore, printf("%c", foo)
cannot tell the difference between char foo
and int foo
. (However, if the value of the datum passed to %c
is outside the range of unsigned char
, the behavior is undefined.)
It worked because it just print the the value of 65
converted to a char type in ASCII table 65 is the letter A so when you put:
int a = 65;
printf("%c", a); //---> a coverted to char type.
Check the ASCII table here ASCII table