TechJ
TechJ

Reputation: 512

Convert raw ASCII data to Hex string

I have the following code to convert raw ASCII data to Hex string. The full c code can be found here

void str2hex(char* inputStr, char* outputStr)
{
   int i;     
   int counter;
    
    i=0;
    counter=0;
    
    while(inputStr[counter] != '\0')
    {
        sprintf((char*)(outputStr+i),"%02X", inputStr[counter]);
        i+=2; counter+=1;
    }
    
    outputStr[i++] = '\0';
}

It works fine for most of the values. But when I am trying the following input from terminal using echo as stdin echo 11223344556677881122334455667788|xxd -r -p| ./CProgram --stdin

11223344556677881122334455667788

It returns the following output

11223344556677FF11223344556677FF

As it can be seen instead of 88 it returns FF.

How can I adjust this code to get 88 instead of FF.

Upvotes: 0

Views: 549

Answers (1)

Some programmer dude
Some programmer dude

Reputation: 409472

There are multiple issues all coalescing into your problem.

The first issue is that it's compiler-defined if char is a signed or unsigned integer type. Your compiler seem to have signed char types.

The second issue is that on most systems today, signed integers are represented using two's complement, where the most significant bit indicates the sign.

The third issue is that vararg functions like printf will do default argument promotion of its arguments. That means types smaller than int will be promoted to int. And that promotion will keep the value of the converted integer, which means negative values will be sign-extended. Sign-extension means that the most significant bit will be copied all the way to the "top" when extending the value. That means the signed byte 0xff will be extended to 0xffffffff when promoted to an int.

Now when your code tries to convert the byte 0x88 it will be treated as the negative number -120, not 136 as you might expect.

There are two possible solutions to this:

  1. Explicitly use unsigned char for the input string:

    void str2hex(const unsigned char* inputStr, char* outputStr);
    
  2. Use the hh prefix in the printf format:

    sprintf((char*)(outputStr+i),"%02hhX", inputStr[counter]);
    

    This tells sprintf that the argument is a single byte, and will mask out the upper bits of the (promoted) integer.

Upvotes: 1

Related Questions