Converting a struct to a hex string in C

Viewed 48

I have the following struct

typedef struct __attribute__((packed)) word {
    uint16_t value;
    uint8_t flag
} Word;

I want to convert it to a hex string. For example if value = 0xabcd and flag = 0x01 I want to get the string 01abcd

if I do some pointer juggling

Word word;
word.value = 0xabcd;
wordk.flag = 0x01;

printf("word: %X\n", *(int *)&word);

I get the output that I want (word: 1ABCD) but this doesn't seem safe and when I tried to do this after looking at some of the answer here

char ptr[3];
memcpy(ptr, word, 3);
printf("word: %02X%02X%02X\n", ptr[2], ptr[1], ptr[0]);

I got word: 01FFFFFFABFFFFFFCD, for some reason the first two bytes are being extended to a full int

4 Answers

There's no real gain from messing around with pointers or type-punning, if all you want is to output the values of the two structure members. Just print them individually:

printf("word: %02x%04x\n", (unsigned int)word.flag, (unsigned int)word.value);

Use a simple sprintf to convert to a string:

int main(void)
{
    Word v = { 0xabcd, 0x01 };
    
    char s[10];
    
    sprintf(s, "%02x%04x", v.flag, v.value);
    
    puts(s);
}

I want to get the string 01abcd

So you want to print the binary representation of the struct on a little endian machine backwards. There's no obvious advantage of using sprintf for this apart from it being quick & dirty to implement.

If you want something with performance, then hacking this out manually isn't rocket science - simply iterate over the struct byte by byte and convert each nibble to the corresponding hex character:

void stringify (const uint8_t* data, size_t size, char* dst)
{
  for(size_t i=0; i<size; i++)
  {
    uint8_t byte = data[size-i-1]; // read starting from the end of the data
    dst[i*2]   = "0123456789ABCDEF"[ byte >> 4  ]; // ms nibble
    dst[i*2+1] = "0123456789ABCDEF"[ byte & 0xF ]; // ls nibble
  }
  dst[size*2] = '\0';
}

This will give "01ABCD" on a little endian machine and "01CDAB" on a big endian machine.

(Optionally add restrict to data and dst parameters but I doubt it will improve performance since the const correctness already blocks aliasing at some extent.)

Could join them mathematically first.

printf("word: %06lx\n", wordk.flag * 0x10000L + word.value);

Using long in case we are on a 16-bit int machine.

Related