Following on this question How to convert a string to hex and vice versa in c??
I run the following code:
#include <stdio.h>
int main (int argc, char *argv[])
{
char str[] = { 0x58, 0x01, 0x02, 0x20, 0x22, 0x00, 0xC5};
char hex[32] = {0}, hex2[32] = {0};
for (int i = 0; i < sizeof(str); i ) {
sprintf(hex i*2, "X", str[i]);
}
for (int i = 0; i < sizeof(str); i ) {
sprintf(hex2 i*2, "X", str[i] & 0xff);
}
printf("hex = %s\nhex2 = %s\n", hex, hex2);
return 0;
}
I get this result:
hex = 580102202200FFFFFFC5
hex2 = 580102202200C5
I wonder why there is more FFFFFF
without 0xFF?
CodePudding user response:
There are many small pieces to the puzzle that needs to be put together.
To begin with it's implementation-defined if char
is signed or unsigned.
If it's signed, then because of the common two's complement the value 0xc5
will actually be negative (it will be the decimal value -59
).
And when a small integer type (like char
) is used as an argument to a variable-argument function like sprintf
, then it will be promoted to int
. If the type is signed and the value is negative, it will be sign extended. So assuming the common 32-bit int
, the signed and negative value 0xc5
will be promoted and sign-extended to 0xffffffc5
.
To solve this problem, the simplest solution is to simply use an explicit unsigned type like uint8_t
(which basically is an alias for unsigned char
).
Besides that I also recommend you use the hh
format type prefix to explicitly say that the argument is a byte.
Put together change to
uint8_t str[] = { 0x58, 0x01, 0x02, 0x20, 0x22, 0x00, 0xC5};
and
sprintf(hex i*2, "hhX", str[i]);
As for the difference made by str[i] & 0xff
, it's because then you mask out the top 24 bits of the int
value. So 0xffffffc5 & 0xff
becomes 0x000000c5
.
CodePudding user response:
Before you go believing some of the things you've been told, stop and consider...
sprintf( dst, "X", str[i] & 0xff);
could be written
sprintf( dst, "X", ( str[i] & 0xff) );
Now, since str[i]
has been defined as a (signed) char
, it should be apparent that there are no extra higher bits involved in this operation.
Instead, the magic of the 0xff is that hexadecimals are unsigned
values.
If the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type is converted to the type of the operand with unsigned integer type.
The compiler will convert the signed byte to unsigned and perform the masking (which is superfluous). This unsigned value 0x## will be promoted to an unsigned integer value passed to the variadic function printf
as 0x000000##...
Careful to whom you confer the term 'advisor'.
The 1st comment explains the solution to your overabundant 'F's...
You've mixed hex notation into a (signed) char
array... Easy to fix...