#include<stdio.h>
int main() {
int i = 3771717;
printf ("%c", i);
return 0;
}
The output is E. Isn't 69 the ASCII for E?
The %c format specifier expects an int argument which is then converted to and unsigned char as printed as a character.
The int value 3771717 gets converted to the unsigned char value 69 as per the conversion rules from a signed integer to unsigned integer. The C standard specifies this is done by repeatedly subtracting one more than the maximum value for unsigned char until it is in range. In practice, that means truncating the value to the low order byte. 3771717 decimal is 398D45 hex so that leaves us with 45 hex which is 69 decimal.
Then the character code for 69 i.e. 'E' is printed.
Related
#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?
%c will only accept values up to 255 included, then it will start from 0 again !
577 % 256 = 65; // (char code for 'A')
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.
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.
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'.
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.
This question already has answers here:
How to print an unsigned char in C?
(6 answers)
Closed 3 years ago.
I'm getting unexpected results when loading a binary file in C.
FILE *bin = NULL;
unsigned long file_length = 0;
bin = fopen("vs.bin", "rb");
fseek(bin, 0, SEEK_END);
file_length = ftell(bin);
fseek(bin, 0, SEEK_SET);
char *buffer = (char *)malloc(file_length);
fread(buffer, 1, file_length, bin);
for(unsigned int i = 0; i < file_length; i++) {
printf("%02x ", buffer[i]);
}
printf("\n");
What I see in the first eight values of output is this:
56 53 48 05 ffffffa4 ffffff8b ffffffef 49
But what I see when I open the binary in a hex editor is this:
56 53 48 05 A4 8B EF 49
What would cause this to happen? There are more instances of this happening throughout but I thought only sharing the first segment would suffice to illustrate the problem.
Thanks for reading.
Change char *buffer to unsigned char *buffer. Also change %02x to %02hhx.
In your C implementation, char is signed. When you read data into a buffer of char, you have signed values. When you use them in an expression (including arguments to printf), some of them have negative values. Additionally, values narrower than int are generally promoted to int. At that point, the char value −92 (which is represented with bits 0xA4) becomes the int value −92 (which is represented with bits 0xFFFFFFA4, in your C implementation).
So you have negative values that are converted to int and then printed with %02x, and %02x shows all the bits of the int. (In %02x, 2 specifies the minimum width; it does not restrict the result to two digits.)
%hhx is a proper conversion specifier for an unsigned char. %x is for unsigned int.
The format specifier %02x specifies the minimum number of digits to be printed out, not the maximum. The values a4, 8b and ef are all negative when interpreted as signed bytes, so what you're seeing is the two's complement representation of these values as 32-bit ints, which is what they're promoted to when passed to printf.
Explicitly name buffer as unsigned char or uint8_t to avoid this unintended sign-extension, and use the correct format specifier (%hhx for lowercase a-f hex digits, %hhX for uppercase).
#include <stdio.h>
int main(void)
{
char i=49;
printf("%d",i);
return 0;
}
Why does the output is 49?
I am using %d to print a character, whereas my character declaration is also wrong.
In C a char means the same thing as a byte; it is the smallest addressable piece of memory, and also a smallest of integer types. 49 is an integer constant of type int having the value 49. '1' is a character constant, that also has type int! And on ASCII systems'1' as the value 49 (the ASCII code of character 1).
printf conversion specifier %d expects the corresponding argument to be an int, whose value is then printed in decimal notation. The remaining arguments after the format string are subject to default argument promotions; each integer type smaller than int is promoted to an int; and float is promoted to double. Since i has an integer type smaller than int, its value (49) is now promoted to an int and to printf it looks exactly the same as if any other integer value 49 was given.
To print the character whose character code is 49, you need to use the %c conversion specifier; printf will then output 1, which is the character by code 49; even now, the argument is promoted to int, and printf internally converts that value to an unsigned char, which then will be output (source):
c
[...] the int argument is converted to an unsigned char, and the resulting character is written. [...]
Addendum: in code
char i = 49.012;
printf("%f", i);
49.012 is a value of type double; this is converted to char-range integer by chopping the decimals, thus the value stored in i is yet again 49; which one can prove by printing it with %d. Now, %f expects that the corresponding argument is of type double but i is converted to an int instead; using an argument of wrong type in call to printf has undefined behaviour, i.e. anything can happen. If one compiles with gcc -Wall, the following error is produced:
warning: format %f expects argument of type double, but argument 2 has type int [-Wformat=]
Updating answer based on comments.
char is an integer type, and you assign 49 to this integer type. The %d conversion specifier prints the value of an integer;
char i=49;
If you print using "%c" you can see the corresponding character of ascii value 49 ie 1
Since you are using "%d" you get the integer value itself.
You can try this
char i='1';
Now try printf("%d",i);
You will get 49
%d,%c,%o,%x... these are called format specifier. it will decide which type of output you want.
in your example, you assigned 49 to i and saying to compiler that you want the output in decimal.
if you try to print the same by substituting %d with %c, then it will print
1 because it assumes the output should be print in the form of char equivalent of the given number
where in ASCII table 49 is 1
and FYI
in the implementation of printf function they will deal '%' symbol followed by the character as special case
if the followed character is valid then it will output
%x is hex
%d is decimal
%i is integer
%c is character
%s is string
%f is float
............... etc
you can google "formal specifier in c" there will be plenty of results
hope this info useful to you.
I expected the code below show two equal lines:
#include <stdio.h>
int main(void) {
//printf("%x %x %x\n", '\x7F', (unsigned char)'\x8A', (unsigned char)'\x8B');
printf("%x %x %x\n", '\x7F', '\x8A', '\x8B');
printf("%x %x %x\n", 0x7F, 0x8A, 0x8B);
return 0;
}
My output:
7f ffffff8a ffffff8b
7f 8a 8b
I know that is maybe a overflow case. But why the ffffff8a (4 bytes)...?
'\x8A' is, according to cppreference,
a single-byte integer character constant, e.g. 'a' or '\n' or '\13'.
What is particularly interesting is the following.
Such constant has type int and a value equal to the representation of c-char in the execution character set as a value of type char mapped to int.
This means that the conversion of '\x8A' to an unsigned int is implementation-defined, because char can be signed or unsigned, depending on the system. If char is signed, as it seems to be the case for you (and is very common), then the value of '\x8A' (which is negative) as a 32-bit int is 0xFFFFFF8A (also negative). However, if char is unsigned, then it becomes 0x0000008A (which is why the commented line in your code works as you'd think it should).
The printf format specifier %x is used to convert an unsigned integer into hexadecimal representation. Although printf expects an unsigned int and you give it an int, and even though the standard says that passing an incorrect type to printf is (generally) undefined behavior, it isn't in your case. This is because the conversion from int to unsigned int is well-defined, even though the opposite isn't.
I'm trying to read in a line of characters, then print out the hexadecimal equivalent of the characters.
For example, if I have a string that is "0xc0 0xc0 abc123", where the first 2 characters are c0 in hex and the remaining characters are abc123 in ASCII, then I should get
c0 c0 61 62 63 31 32 33
However, printf using %x gives me
ffffffc0 ffffffc0 61 62 63 31 32 33
How do I get the output I want without the "ffffff"? And why is it that only c0 (and 80) has the ffffff, but not the other characters?
You are seeing the ffffff because char is signed on your system. In C, vararg functions such as printf will promote all integers smaller than int to int. Since char is an integer (8-bit signed integer in your case), your chars are being promoted to int via sign-extension.
Since c0 and 80 have a leading 1-bit (and are negative as an 8-bit integer), they are being sign-extended while the others in your sample don't.
char int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061
Here's a solution:
char ch = 0xC0;
printf("%x", ch & 0xff);
This will mask out the upper bits and keep only the lower 8 bits that you want.
Indeed, there is type conversion to int.
Also you can force type to char by using %hhx specifier.
printf("%hhX", a);
In most cases you will want to set the minimum length as well to fill the second character with zeroes:
printf("%02hhX", a);
ISO/IEC 9899:201x says:
7 The length modifiers and their meanings are:
hh Specifies that a following d, i, o, u, x, or X conversion specifier applies to a
signed char or unsigned char argument (the argument will have
been promoted according to the integer promotions, but its value shall be
converted to signed char or unsigned char before printing); or that
a following
You can create an unsigned char:
unsigned char c = 0xc5;
Printing it will give C5 and not ffffffc5.
Only the chars bigger than 127 are printed with the ffffff because they are negative (char is signed).
Or you can cast the char while printing:
char c = 0xc5;
printf("%x", (unsigned char)c);
You can use hh to tell printf that the argument is an unsigned char. Use 0 to get zero padding and 2 to set the width to 2. x or X for lower/uppercase hex characters.
uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"
Edit: If readers are concerned about 2501's assertion that this is somehow not the 'correct' format specifiers I suggest they read the printf link again. Specifically:
Even though %c expects int argument, it is safe to pass a char because of the integer promotion that takes place when a variadic function is called.
The correct conversion specifications for the fixed-width character types (int8_t, etc) are defined in the header <cinttypes>(C++) or <inttypes.h> (C) (although PRIdMAX, PRIuMAX, etc is synonymous with %jd, %ju, etc).
As for his point about signed vs unsigned, in this case it does not matter since the values must always be positive and easily fit in a signed int. There is no signed hexideximal format specifier anyway.
Edit 2: ("when-to-admit-you're-wrong" edition):
If you read the actual C11 standard on page 311 (329 of the PDF) you find:
hh: Specifies that a following d, i, o, u, x, or X conversion specifier applies to a signed char or unsigned char argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to signed char or unsigned char before printing); or that a following n conversion specifier applies to a pointer to a signed char argument.
You are probably storing the value 0xc0 in a char variable, what is probably a signed type, and your value is negative (most significant bit set). Then, when printing, it is converted to int, and to keep the semantical equivalence, the compiler pads the extra bytes with 0xff, so the negative int will have the same numerical value of your negative char. To fix this, just cast to unsigned char when printing:
printf("%x", (unsigned char)variable);
You are probably printing from a signed char array. Either print from an unsigned char array or mask the value with 0xff: e.g. ar[i] & 0xFF. The c0 values are being sign extended because the high (sign) bit is set.
Try something like this:
int main()
{
printf("%x %x %x %x %x %x %x %x\n",
0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}
Which produces this:
$ ./foo
c0 c0 61 62 63 31 32 33