Why printf show false value of an hex number [duplicate] - c

This question already has answers here:
Why does printf not print out just one byte when printing hex?
(5 answers)
Printing hexadecimal characters in C
(7 answers)
How to print 1 byte with printf?
(4 answers)
Closed 5 years ago.
Code
char a;
a = 0xf1;
printf("%x\n", a);
Output
fffffff1
printf() show 4 bytes, that exactly we have one byte in a.
What is the reason of this misbehavior?
How can i correct it?

What is the reason of this misbehavior?
This question looks strangely similar to another I have answered; it even contains a similar value (0xfffffff1). In that answer, I provide some information required to understand what conversion happens when you pass a small value (such as a char) to a variadic function such as printf. There's no point repeating that information here.
If you inspect CHAR_MIN and CHAR_MAX from <limits.h>, you're likely to find that your char type is signed, and so 0xf1 does not fit as an integer value inside of a char.
Instead, it ends up being converted in an implementation-defined manner, which for the majority of us means it's likely to end up with one of the high-order bits becoming the sign bit. When these values are promoted to int (in order to pass to printf), sign extension occurs to preserve the value (that is, a char that has a value of -1 should be converted to an int that has a value of -1 as an int, so too is the underlying representation for your example likely to be transformed from 0xf1 to 0xfffffff1).
printf("CHAR_MIN .. CHAR_MAX: %d .. %d\n", CHAR_MIN, CHAR_MAX);
printf("Does %d fit? %s\n", '\xFF', '\xFF' >= CHAR_MIN && '\xFF' <= CHAR_MAX ? "Yes!"
: "No!");
printf("%d %X\n", (char) -1, (char) -1); // Both of these get converted to int
printf("%d %X\n", -1, -1); // ... and so are equivalent to these
How can i correct it?
Declare a with a type that can fit the value 0xf1, for example int or unsigned char.

printf is a variable argument function, so the compiler does its best but cannot check strict compliance between format specifier and argument type.
Here you're passing a char with a %x (integer, hex) format specifier.
So the value is promoted to a signed integer (because > 127: negative char and char is signed on most systems, on yours that's for sure)
Either:
change a to int (simplest)
change a to unsigned char (as suggested by BLUEPIXY) that takes care of the sign in the promotion
change format to %hhx as stated in the various docs (note that on my gcc 6.2.1 compiler hhx is not recognized, even if hx is)
note that the compiler warns you before reaching printf that you have a problem:
gcc -Wall -Wpedantic test.c
test.c: In function 'main':
test.c:6:5: warning: overflow in implicit constant conversion [-Woverflow]
a = 0xf1;

You should use int a instead of char a because char is unsigned and can store only 1 byte from 0 to 255.
And hex number need many storage to store it, and also int storage size is 2 or 4 bytes. So it's good to use int here to store hex number.

Related

Printing the hex value stored as a string gives unexpected output

I have in C language hex numbers defined in string:
char chars[] = "\xfb\x54\x9c\xb2\x10\xef\x89\x51\x2f\x0b\xea\xbb\x1d\xaf\xad\xf8";
Then I want to compare the values with another. It is not working and if I print the value like:
printf("%02x\n", chars[0]);
it writes fffffffb. Why is that and how to get fb value exactly?
This is because of the sign extension.
Change
printf("%02x\n", chars[0]);
to
printf("%02x\n", (unsigned char)chars[0]);
The %x format specifier will read 4 bytes on 32bit machine. As you have declared chars as the character array, when fetching the value fb(negative value) will be sign extended as fffffffb, where the MSB of fb is set to all other bits before it.
Refer this for more details sign extension
If you would have declared char chars[] as unsigned char chars[] then the print would have been as expected.
As per the standard mentioning regarding the %x format specifier with fprintf()
o,u,x,X
The unsigned int argument is converted to unsigned octal (o), unsigned
decimal (u), or unsigned hexadecimal notation (x or X) in the style dddd; [...]
So, the expected type of argument to %x is unsigned int.
Now, printf() being a variadic function, only default promotion rule is applied to its arguments. In your code, chars being an array of type char (signedness of which is implementation dependent), in case of
printf("%02x\n", chars[0]);
the value of chars[0] get promoted to an int which is not the expected type for %x. Hence, the output is wrong, as int and unsigned int are not the same type. [Refer ยง6.7.2, C11]. So, without an explicit cast like
printf("%02x\n", (unsigned int)chars[0]);
it invokes undefined behaviour.
FWIW, if you're having a C99 supported compiler, you can make use of the hh length modifier to work around this, like
printf("%02hhx\n", (unsigned char)chars[0]);
It's because of sign extension.
This will work as you expect:
printf("%02x\n", (unsigned char)chars[0]);

printf adds extra `FFFFFF` to hex print from a char array [duplicate]

This question already has answers here:
Why does printf not print out just one byte when printing hex?
(5 answers)
Closed 6 years ago.
Consider the following simplified code bellow. I want to extract some binary data/stream from a file and print it to the standard output in Hexadecimal format.
I got extra 3 bytes 0xFFFFFF. What's wrong? From where did the extra bytes come?
output
in:
2000FFFFFFAF00690033005A00
out:
2000FFFFFFAF00690033005A00
program.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
int i;
char raw[10] = {0x20,0x00,0xAF,0x00,0x69,0x00,0x33,0x00,0x5A,0x00};
FILE *outfile;
char *buf;
printf("in:\n\t");
for( i=0; i<10; i++ )
printf("%02X", raw[i]);
outfile = fopen("raw_data.bin", "w+b");
fwrite(raw, 1, 10, outfile);
buf = (char *) malloc (32 * sizeof(char));
fseek(outfile, 0, SEEK_SET);
fread(buf, 1, 10, outfile);
printf("\nout:\n\t");
for( i=0; i<10; i++ )
printf("%02X", buf[i]);
printf("\n");
fclose(outfile);
return 0;
}
Sign extension. Your compiler is implementing char as a signed char. When you pass the chars to printf they are all being sign extended during their promotion to ints. When the first bit is a 0 this doesn't matter, because it gets extended with 0s.
0xAF in binary is 10101111 Since the first bit is a 1, when passing it to printf it is extended with all 1s in the conversion to int making it 11111111111111111111111110101111, which is 0xFFFFFFAF, the hex value you have.
Solution: Use unsigned char (instead of char) to prevent the sign extension from occurring in the call
const unsigned char raw[] = {0x20,0x00,0xAF,0x00,0x69,0x00,0x33,0x00,0x5A,0x00};
All of these values in your original example are being sign extended, it's just that 0xAF is the only one with a 1 in the first bit.
Another simpler example of the same behavior (live link):
signed char c = 0xAF; // probably gives an overflow warning
int i = c; // extra 24 bits are all 1
assert( i == 0xFFFFFFAF );
That's because 0xAF when converted from a signed character to a signed integer is negative (it is sign extended), and the %02X format is for unsigned arguments and prints the converted value as FFFFFFAF.
The extra characters appear because printf %x will never silently truncate digits off of a value. Values which are non-negative get sign extended as well, but that's just adding zero bits and the value fits in 2 hex digits, so printf %02 can do with a two digit output.
Note that there are 2 C dialects: one where plain char is signed, and one where it is unsigned. In yours it is signed. You may change it using an option, e.g. gcc and clang support -funsigned-char and -fsigned-char.
The printf() is a variadic function and its additional arguments (corresponding with ... part of its prototype) are subject to default argument promotions, thus char is promoted to int.
As your char has signed1, two's complement representation the most significant bit is set to one for 0xAF element. During promotion signed bit is propagated, resulting 0xFFFFFFAF of int type, as presumably sizeof(int) = 4 in your implementation.
By the way you are invoking undefined behaviour, since %X format specifier should be used for object of type unsigned int or at least for int with MSB that is unset (this is common, widely accepted practice).
As suggested you may consider use of unambiguous unsigned char type.
1) Implementation may choose between signed and unsigned represention of char. It's rather common that char is signed, but you cannot take it for granted for every other compiler on the planet. Some of them may allow to choose between these two modes, as mentioned in Jens's answer.

why is -1>strlen(t) true in C? [duplicate]

This question already has answers here:
void main() { if(sizeof(int) > -1) printf("true"); else printf("false"); ; [duplicate]
(3 answers)
Why sizeof(int) is not greater than -1? [duplicate]
(2 answers)
Closed 7 years ago.
Working on this little piece of code in VS2013, but for some reason it doesn't print.it seems that -1>strlen(str)
Anyone got an idea what i'm doing wrong
char *str="abcd";
if(-1<strlen(str))
printf("The size of the string is %d", strlen(str));
return 0;
Anyone got an idea what i'm doing wrong
strlen() returns a size_t, which is an unsigned integer type. -1 interpreted as an unsigned integer is a large value, so it ends up being greater than the length of your string. You can use the -Wsign-compare flag in gcc and some other compilers to warn you when you try to compare signed and unsigned values.
Also, it doesn't make much sense to compare the length of a string to -1. A length can never be negative; it's always going to be 0 or greater. So you'll probably want to rewrite your code to test against 0, or otherwise properly implement whatever condition you're trying to test for.
if(-1<strlen(str))
printf("The size of the string is %d", strlen(str));
In this code, you might reasonably expect the test to always succeed and the printf() to execute, since the length is always 0 or more. But you're finding that the test actually fails and the printf() never happens because -1 is promoted to an unsigned so that it can be compared to a size_t. The easy solution is to remove the condition altogether: you know the test will always succeed, so there's no need for it. Just remove the if*:
printf("The size of the string is %zu", strlen(str));
*Also, change the print format specifier from %d to %zu since, as Matt McNabb pointed out in a comment, you're trying to print a size_t.
strlen(str) returns an unsigned integer. When comparing signed integer with unsigned integer, the compiler converts the signed value to unsigned. When converted to unsigned, -1 becomes 2^32 - 1 (assuming that strlen returns a 32 bit integer), which is greater than the length of the string you are comparing with.
strlen returns a value of type size_t. This is an unsigned integral type.
The rule in C for when comparing a signed value with a value of the corresponding unsigned type, is that the signed value is converted to the unsigned value.
If the values are of different sized types, for example if your system has 4-byte int and 8-byte size_t, then the rule is that the value of smaller type is converted to the value of the larger type.
Either way this means that -1 is converted to size_t, resulting in SIZE_MAX which is a large positive value. (unsigned types cannot hold negative values).
This large positive value is greater than the length of your string, so the less-than comparison returns false.

Use of unsigned int in different cases? [duplicate]

This question already has answers here:
Unsigned int in C behaves negative
(8 answers)
Closed 8 years ago.
I want to ask what is the difference between these two cases ?
Case1:
unsigned int i;
for(i=10;i>=0;i--)
printf("%d",i);
It will result in an infinite loop!
Case2:
unsigned int a=-5;
printf("%d",a);
It will print -5 on the screen.
Now the reason for case 1 is that i is declared as unsigned int so it can not take negative values,hence will always be greater than 0.
But in case 2, if a cannot take negative values, why -5 is being printed???
What is the difference between these two cases?
The difference is that you are printing a as a signed integer.
printf("%d",a);
so while a may be unsigned, then the %d is asking to print the binary value as a signed value. If you want to print it as a unsigned value, then use
printf("%u",a);
Most compilers will warn you about incompatible use of of parameters to printf -- so you could probably catch this by looking at all the warnings and fix it.
When a -ve value is assigned to an unsigned variable, it can't hold that value and that value is added to UINT_MAX and finally you get a positive value.
Note that using wrong specifier to print a data type invokes undefined behavior.
See C11: 7.21.6 p(6):
If a conversion specification is invalid, the behavior is undefined.282)
unsigned int a=-5;
printf("%u",a); // use %u to print unsigned
will print the value of UINT_MAX - 5.
i is declared unsigned so it can not take negative values
That is correct. Most optimizing compilers will notice that, drop the condition from the loop, and issue a warning.
In case 2, if a can not take negative values, why -5 is being printed?
Because on your platform int and unsigned int have such a representation that assigning -5 to unsigned int and then passing it to printf preserves the representation of -5 in the form that lets printf produce the "correct" result.
This is true on your platform, but other platforms may be different. That is why the standard considers this behavior undefined (i.e. printf could produce any output at all). If you print using the unsigned format specifier, you will see a large positive number.

Why doesn't assigning a negative integer to an unsigned int cause an error?

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
unsigned int i;
i = -12;
printf("%d\n" , i);
system("pause");
return 0;
}
I run the above code in Visual Studio 2012. Because I know unsigned refers to nonnegative numbers, I expected the program to report an error. Why does it still run smoothly and print the output?
As 200_success alluded to, there are two things going on here that are combining to produce the correct output, despite the obvious problems of mixing unsigned and signed integer values.
First, the line i = -12 is implicitly converting the (signed) int literal value -12 to an unsigned int. The bits being stored in memory don't change. It's still 0xfffffff4, which is the twos-complement representation of -12. An unsigned int, however, ignores the sign bit (the uppermost bit) and instead treats it as part of the value, so as an unsigned int, this value (0xfffffff4) is interpreted as the number 4294967284. The bottom line here is that C has very loose rules about implicit conversion between signed and unsigned values, especially between integers of the same size. You can verify this by doing:
printf("%u\n", i);
This will print 4294967284.
The second thing that's going on here is that printf doesn't know anything about the arguments you've passed it other than what you tell it via the format string. This is essentially true for all functions in C that are defined with variable argument lists (e.g., int printf(const char *fmt, ...); ) This is because it is impossible for the compiler to know exactly what types of arguments might get passed into this function, so when the compiler generates the assembly code for calling such a function, it can't do type-checking. All it can do is determine the size of each argument, and push the appropriate number of bytes onto the stack. So when you do printf("%d\n", i);, the compiler is just pushing sizeof(unsigned int) bytes onto the stack. It can't do type checking because the function prototype for printf doesn't have any information about the types of any of the arguments, except for the first argument (fmt), which it knows is a const char *. Any subsequent arguments are just copied as generic blobs of a certain number of bytes.
Then, when printf gets called, it just looks at the first sizeof(unsigned int) bytes on the stack, and interprets them how you told it to. Namely, as a signed int value. And since the value stored in those bytes is still just 0xfffffff4, it prints -12.
Edit: Note that by stating that the value in memory is 0xfffffff4, I'm assuming that sizeof(unsigned int) on your machine is 4 bytes. It's possible that unsigned int is defined to be some other size on your machine. However, the same principles still apply, whether the value is 0xfff4 or 0xfffffffffffffff4, or whatever it may be.
This question is similar to this Objective C question. The short answer is, two wrongs make a right.
i = -12 is wrong, in that you are trying to store a negative number in an unsigned int.
printf("%d\n", i) is wrong, in that you are asking printf to interpret an unsigned int as a signed int.
Both of those statements should have resulted in compiler warnings. However, C will happily let you abuse the unsigned int as just a place to store some bits, which is what you've done.
i = -12; is well-defined. When you assign an out-of-range value to an unsigned int, the value is adjusted modulo UINT_MAX + 1 until it comes within range of the unsigned int.
For example if UINT_MAX is 65535, then i = -12 results in i having the value of 65536 - 12 which is 65524.
It is undefined behaviour to mismatch the argument types to printf. When you say %d you must supply an int (or a smaller type that promotes to int under the default argument promotions).
In practice what will usually happen is that the system interprets the bits used to represent the unsigned int as if they were bits used to represent a signed int; of course since it is UB this is not guaranteed to work or even be attempted.
You are indeed saving the -12 as an integer and telling printf (by using %d) that it is a normal int, so it interprets the contents of said variable as an int and prints a -12.
If you used %u in printf you would see what it is you're really storing when intepreting the contents as an unsigned int.
printing may work (as explained by many above) but avoid using i in your code for further calculation. It will give not retain the sign.

Resources