4
#include<stdio.h>
int main()
{
  int i = 577;
  printf("%c",i);
  return 0;
}

After compiling, its giving output "A". Can anyone explain how i'm getting this?

dbush
  • 205,898
  • 23
  • 218
  • 273

5 Answers5

9

%c will only accept values up to 255 included, then it will start from 0 again !

577 % 256 = 65; // (char code for 'A')

axelduch
  • 10,769
  • 2
  • 31
  • 50
7

This has to do with how the value is converted.

The %c format specifier expects an int argument and then converts it to type unsigned char. The character for the resulting unsigned char is then written.

Section 7.21.6.1p8 of the C standard regarding format specifiers for printf states the following regarding c:

If no l length modifier is present, the int argument is converted to an unsigned char, and the resulting character is written.

When converting a value to a smaller unsigned type, what effectively happens is that the higher order bytes are truncated and the lower order bytes have the resulting value.

Section 6.3.1.3p2 regarding integer conversions states:

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.

Which, when two's complement representation is used, is the same as truncating the high-order bytes.

For the int value 577, whose value in hexadecimal is 0x241, the low order byte is 0x41 or decimal 65. In ASCII this code is the character A which is what is printed.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • Should it matter what representation is used for negatives -- there are no negatives? – Neil Jul 01 '22 at 18:22
  • 1
    It matters if one's complement or sign-and-magnitude are used. For example, -1 will always be converted to 255 as per the above rule, but in sign-and-magnitude -1 is represented as 0x80000001 which means the low order byte is 1, not 255. – dbush Jul 01 '22 at 18:25
  • 577 is the same in all the integer-representations, or are you are talking in general when the argument could be negative? – Neil Jul 01 '22 at 18:31
  • 1
    @Neil In the general case it matters. Positive values always have the same representation. – dbush Jul 01 '22 at 18:33
  • dbush, The output does not change if ones' complement or sign-magnitude are used instead of 2's complement. `char ch = -1; printf("%c",ch);` would print the same if `char` was _signed_ under all 3 encodings. The conversion to `unsigned char` is defined arithmetically, not by extracting the lower byte. – chux - Reinstate Monica Jul 03 '22 at 16:46
  • @chux-ReinstateMonica That's what I meant: the result doesn't change based on the representation, but the equivalence of truncating the higher order bytes no longer applies. – dbush Jul 03 '22 at 16:49
  • Introducing high/low byte discussion unnecessarily specific to 2's complement when a "mod" explanation would cover all 3. IAC, likely irrelevant with next version of C with only 2's complement. – chux - Reinstate Monica Jul 03 '22 at 16:57
3

How does printing 577 with %c output "A"?

With printf(). "%c" matches an int argument*1. The int value is converted to an unsigned char value of 65 and the corresponding character*2, 'A' is then printed.

This makes no difference if a char is signed or unsigned or encoded with 2's complement or not. There is no undefined behavior (UB). It makes no difference how the argument is passed, on the stack, register, or .... The endian of int is irrelevant. The argument value is converted to an unsigned char and the corresponding character is printed.


*1All int values are allowed [INT_MIN...INT_MAX].

When a char value is passed as ... argument, it is first converted to an int and then passed.

char ch = 'A';
printf("%c", ch); // ch is converted to an `int` and passed to printf().

*2 65 is an ASCII A, the ubiquitous encoding of characters. Rarely other encodings are used.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
2

577 in hex is 0x241. The ASCII representation of 'A' is 0x41. You're passing an int to printf but then telling printf to treat it as a char (because of %c). A char is one-byte wide and so printf looks at the first argument you gave it and reads the least significant byte which is 0x41.

To print an integer, you need to use %d or %i.

Daniel Walker
  • 6,380
  • 5
  • 22
  • 45
2

Just output the value of the variable i in the hexadecimal representation

#include <stdio.h>

int main( void )
{
    int i = 577;

    printf( "i = %#x\n", i );
}

The program output will be

i = 0x241

So the least significant byte contains the hexadecimal value 0x41 that represents the ASCII code of the letter 'A'.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Is the fact that the least significant byte is read due to the Endianness of the system? – Daniel Walker Jul 01 '22 at 17:57
  • 2
    @DanielWalker It does not depend on that. Using the conversion specifier c always outputs the least significant byte of an integer. Otherwise you had unspecified behavior in this code snippet int i = 'A'; printf( "%c", i ); – Vlad from Moscow Jul 01 '22 at 18:00