Why printing unsigned char outputs such a great number? - c

I am printing variable of type unsigned char (8bits long).
But the printf() outputs a huge number outside the range of the variable I am printing.
unsigned char c;
printf("%u",c);
The output is:
21664
I don't know what is going on?

It has undefined behaviour because a is not initialized .
To print decimal value of character you can do like this -
#include <stdio.h>
int main()
{
unsigned char a='A';
printf("%d",a);
return 0;
}
Which will print ascii value of A that is 65.

Modify to printf( "%u", (unsigned int)c ). Otherwise printf will get 2 bytes from stack - one with c value and other with random byte.

because print format is %u is unsigned int,but the c is a unsigned char. printf parse c point as a unsigned int point, program read undefined buffer.

Using wrong format specifier leads to undefined behavior.
%u is for unsigned int not for unsigned char

The output is: 21664 I don't know what is going on?
To print the value of that char you have to give a value to that char, if not you get undefined behavior.
If you need to print its decimal value, just use %d(%u its ok also here) because CHAR is also an INT
printf("The decimal value of CHAR is\t%d",c);
This can help you also to understand it:
#include <stdio.h>
int main(void){
unsigned char c = 'A';
printf("The decimal value of CHAR is\t%d\n",c);
printf("The decimal value of CHAR is\t%u\n",c);
return 0;
}
Output:
The decimal value of CHAR is 65
The decimal value of CHAR is 65

There isn't any error in your code. As far as the length of the printed result is concerned it is printing the value of unsigned int instead of unsigned char. Because of wrong format specifier. The value should be smaller than 65535 and it is.
By the way to print an unsigned char use format specifier %h.
This will tell the compiler that the variable is of type unsigned short and will do the job for you.

just declare your unsigned char as
unsigned char ch=234;
and your printf will work correctly

Related

How to get hexadecimal val of char in c

So im new to C and im so confused. I dont know how to get a hexadecimal value of a char.
how would i get the chars hexadecimal val below???
char a = 'a';
With char a = 'a';, a has a value. Depending on how we want to see that value:
To print that value as a (ASCII) character: printf("%c\n", a);
To print its value in decimal: printf("%d\n", a);
To print its value in hexadecimal: printf("%x\n", a);
In all 3 cases, the value in a is promoted to an int as an argument to a ... function. It is that int code is printing.
As a char may be signed or unsigned, additional considerations are needed when a < 0 or in rare implementations where char is as wide as an int.

Assigned negative value to char in c prints "?" on macOS

#include<stdio.h>
int main(){
signed char c; //range of signed char is -128 to 127
char d; //this is basically a signed char, if I am not wrong
unsigned char e; //range of unsigned char is 0 to 255
c = -12;
d = -12;
e = 255;
printf("%c\n", c);
printf("%c\n", d);
printf("%c\n", e);
return 0;
}
These all char gets printed as '?'.
Trying to understand why? is it a garbage value or actually a same char assigned to different values? which is highly not possible.
When you pass a char, signed char, or unsigned char to printf, it is promoted to an int value (in normal C implementations, where char is narrower than int). For a %c conversion specification , printf converts that int to unsigned char and writes the resulting character.
When the character is not a printable character of the character set in use, displaying a “?” is a common behavior.
Whether char is signed or unsigned is implementation-defined, although it remains a distinct type, separate from both signed char and unsigned char.

Collateral effect using the sprintf function

How come when I use the sprintf function somehow the variable A value changed?
#include <stdio.h>
int main(void) {
short int A = 8000;
char byte_1[2] /*0001 1111 01000 0000*/, total[4];
sprintf(byte_1, "%i", A);
printf("%s\n", byte_1);// displayed on the screen 8000
printf("%i\n", A); // displayed on the screen 12336
}
byte_1 is too short to receive the representation of A in decimal: it only has space for 1 digit and the null terminator and sprintf does not have this information, so it will attempt to write beyond the end of the byte_1 array, causing undefined behavior.
make byte_1 larger, 12 bytes is a good start.
sprintf is inherenty unsafe. Use snprintf that protects against buffer overrun:
snprintf(byte_1, sizeof byte_1, "%i", A);
Here is a potential explanation for this unexpected output: imagine byte_1 is located in memory just before A. sprintf converts the value of A to five characters '8', '0', '0', '0' and '\0' that overflows the end of byte_1, and overwrites the value of variable A itself. When you later print the value of A with printf, A no longer has value 8000, but rather 12336... Just one of an infinite range of possible effects of undefined behavior.
Try this corrected version:
#include <stdio.h>
int main(void) {
short int A = 8000;
char byte_1[12], total[4];
snprintf(byte_1, sizeof byte_1, "%i", A);
printf("%s\n", byte_1);
printf("%i\n", A);
return 0;
}
The text representation of the value stored in A is ”8000” - that’s four characters plus the string terminator, so byte_1 needs to be at least 5 characters wide. If you want byte_1 to store the representation of any unsigned int, you should make it more like 12 characters wide:
char byte_1[12];
Two characters is not enough to store the string ”8000”, so whensprintf writes to byte_1, those extra characters are most likely overwriting A.
Also note that the correct conversion specifier for an unsigned int is %u, not %i. This will matter when trying to format very large unsigned values where the most significant bit is set. %i will attempt to format that as a negative signed value.
Edit
As chrqlie pointed out, the OP had declared A as short int - for some reason, another answer had changed that to unsigned int and that stuck in my head. Strictly speaking, the correct conversion specifier for a short int is %hd if you want signed decimal output.
For the record, here's a list of some common conversion specifiers and their associated types:
Specifier Argument type Output
--------- ------------- ------
i,d int Signed decimal integer
u unsigned int Unsigned decimal integer
x,X unsigned int Unsigned hexadecimal integer
o unsigned int Unsigned octal integer
f float, double Signed decimal float
s char * Text string
c char Single character
p void * Pointer value, implementation-defined
For short and long types, there are some length modifiers:
Specifier Argument type Output
--------- ------------- ------
hd short signed decimal integer
hhd char signed decimal integer
ld long signed decimal integer
lld long long signed decimal integer
Those same modifiers can be applied to u, x, X, o, etc.
byte_1 is too small for the four digits of "A". It only has enough room for a single digit, and the null (\0) terminator. If you make byte_1 an array of 5 bytes, one for each digit and the null byte, it will be able to fit "A".
#include <stdio.h>
int main(void) {
unsigned int A = 8000;
char byte_1[5], total[4];
sprintf(byte_1, "%i", A);
printf("%s\n", byte_1);
printf("%i\n", A);
return 0;
}
Basically, messing around with memory and trying to put values into variables that are too small for them, is undefined behavior. This is legal but objectively dangerous in C, and no program should be accessing memory like this.
sprintf(byte_1, "%i", A);
Format specifier needs to agree to the variable type.
I suggest the following change:
sprintf(byte_1, "%c", A);
printf("%c\n", byte_1);
EDIT: So an additional change after performing the change above, is to also change A so it is of the same type as byte_1. This will force you to change the value in your example to match the range of char types. Notice that using a function to protect you for overflowing is just a bad solution. Instead, it is your responsibility as a designer of this code to choose the proper tools for the job. When working with char variables, you need to use char-like containers. Same goes with integers, floats, strings, etc. If you have a 1 kilogram of sugar, you want to use a 1kg container to hold this amount. You wouldn't use a cup (250g) as, as you see, it overflows. Happy codding in C!

C - display char as hex

I want to print the ASCII code of a char in hex; for example, for
char a = 0xA5;
I want to print A5 on the console. Here is what I have tried:
char a = 0xA5;
printf("%02X", a);
but i get FFFFFFA5. How could I solve this?
Cast the value to unsigned char, then cast again to unsigned int to be printed via %X.
char a = 0xA5;
printf("%02X", (unsigned int)(unsigned char)a);
Note that conversion to signed integer which is not capable to store original value is implementation-defined, but conversion to unsigned integer is defined, according to N1256 6.3.1.3
The "problem" is called sign extension -- parameteres are passed as int by default so a char would be converted to int and in the process the sign extension would means that the extra f are added -- make the char unsigned like this
unsigned char a = 0xA5;
printf("%02X", a);
and the compiler will understand how to treat your data.

are int and char represented using the same bits internally by gcc?

I was playing around with unicode characters (without using wchar_t support) just for fun. I'm only using the regular char data type. I noticed that while printing them in hex they were showing up full 4 bytes instead of just one byte.
For ex. consider this c file:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *s = (char *) malloc(100);
fgets(s, 100, stdin);
while (s && *s != '\0') {
printf("%x\n", *s);
s++;
}
return 0;
}
After compiling with gcc and giving input as 'cent' symbol (hex: c2 a2) I get the following output
$ ./a.out
¢
ffffffc2: ?
ffffffa2: ?
a:
So instead of just printing c2 and a2 I got the whole 4 bytes as if it's an int type.
Does this mean char is not really 1-byte in length, ascii made it look like 1-byte?
Maybe the reason why the upper three bytes become 0xFFFFFF needs a bit more explanation?
The upper three bytes of the value printed for *s have a value of 0xFF due to sign extension.
The char value passed to printf is extended to an int before the call to printf.
This is due to C's default behaviour.
In the absence of signed or unsigned, the compiler can default to interpret char as signed char or unsigned char. It is consistently one or the other unless explicitly changed with a command line option or pragma's. In this case we can see that it is signed char.
In the absence of more information (prototypes or casts), C passes:
int, so char, short, unsigned char unsigned short are converted to int. It never passes a char, unsigned char, signed char, as a single byte, it always passes an int.
unsigned int is the same size as int so the value is passed without change
The compiler needs to decide how to convert the smaller value to an int.
signed values: the upper bytes of the int are sign extended from the smaller value, which effectively copies the top, sign bit, upwards to fill the int. If the top bit of the smaller signed value is 0, the upper bytes are filled with 0. If the top bit of the smaller signed value is 1, the upper bytes are filled with 1. Hence printf("%x ",*s) prints ffffffc2
unsigned values are not sign extended, the upper bytes of the int are 'zero padded'
Hence the reason C can call a function without a prototype (though the compiler will usually warn about that)
So you can write, and expect this to run (though I would hope your compiler issues warnings):
/* Notice the include is 'removed' so the C compiler does default behaviour */
/* #include <stdio.h> */
int main (int argc, const char * argv[]) {
signed char schar[] = "\x70\x80";
unsigned char uchar[] = "\x70\x80";
printf("schar[0]=%x schar[1]=%x uchar[0]=%x uchar[1]=%x\n",
schar[0], schar[1], uchar[0], uchar[1]);
return 0;
}
That prints:
schar[0]=70 schar[1]=ffffff80 uchar[0]=70 uchar[1]=80
The char value is interpreted by my (Mac's gcc) compiler as signed char, so the compiler generates code to sign extended the char to the int before the printf call.
Where the signed char value has its top (sign) bit set (\x80), the conversion to int sign extends the char value. The sign extension fills in the upper bytes (in this case 3 more bytes to make a 4 byte int) with 1's, which get printed by printf as ffffff80
Where the signed char value has its top (sign) bit clear (\x70), the conversion to int still sign extends the char value. In this case the sign is 0, so the sign extension fills in the upper bytes with 0's, which get printed by printf as 70
My example shows the case where the value is unsigned char. In these two cases the value is not sign extended because the value is unsigned. Instead they are extended to int with 0 padding. It might look like printf is only printing one byte because the adjacent three bytes of the value would be 0. But it is printing the entire int, it happens that the value is 0x00000070 and 0x00000080 because the unsigned char values were converted to
int without sign extension.
You can force printf to only print the low byte of the int, by using suitable formatting (%hhx), so this correctly prints only the value in the original char:
/* Notice the include is 'removed' so the C compiler does default behaviour */
/* #include <stdio.h> */
int main (int argc, const char * argv[]) {
char schar[] = "\x70\x80";
unsigned char uchar[] = "\x70\x80";
printf("schar[0]=%hhx schar[1]=%hhx uchar[0]=%hhx uchar[1]=%hhx\n",
schar[0], schar[1], uchar[0], uchar[1]);
return 0;
}
This prints:
schar[0]=70 schar[1]=80 uchar[0]=70 uchar[1]=80
because printf interprets the %hhx to treat the int as an unsigned char. This does not change the fact that the char was sign extended to an int before printf was called. It is only a way to tell printf how to interpret the contents of the int.
In a way, for signed char *schar, the meaning of %hhx looks slightly misleading, but the '%x' format interprets int as unsigned anyway, and (with my printf) there is no format to print hex for signed values (IMHO it would be a confusing).
Sadly, ISO/ANSI/... don't freely publish our programming language standards, so I can't point to the specification, but searching the web might turn up working drafts. I haven't tried to find them. I would recommend "C: A Reference Manual" by Samuel P. Harbison and Guy L. Steele as a cheaper alternative to the ISO document.
HTH
No. printf is a variable argument function, arguments to a variable argument function will be promoted to an int. And in this case the char was negative, so it gets sign extended.
%x tells printf that the value to print is an unsigned int. So, it promotes the char to an unsigned int, sign extending as necessary and then prints out the resulting value.

Resources