Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use printf to print character string in hexadecimal format, distorted results

Tags:

c

printf

I want to print a character string in hexadecimal format on machine A. Something like:

ori_mesg = gen_rdm_bytestream (1400, seed)
sendto(machine B, ori_mesg, len(mesg))

On machine B

recvfrom(machine A, mesg)

mesg_check = gen_rdm_bytestream (1400, seed)

for(i=0;i<20;i++){
    printf("%02x ", *(mesg+i)& 0xFF);
}
printf("\n");
for(i=0; i<20; i++){
    printf("%02x ", *(mesg_check+i));
}
printf("\n");

seed varies among 1, 2, 3, ...

The bytes generation funcion is:

u_char *gen_rdm_bytestream (size_t num_bytes, unsigned int seed)
{
    u_char *stream = malloc (num_bytes+4);
    size_t i;

    u_int16_t seq = seed;
    seq = htons(seq);
    u_int16_t tail = num_bytes;
    tail = htons(tail);
    memcpy(stream, &seq, sizeof(seq));
    srand(seed);
    for (i = 3; i < num_bytes+2; i++){
        stream[i] = rand ();
    }
    memcpy(stream+num_bytes+2, &tail, sizeof(tail));

    return stream;
}

But I got results from printf like:

00 01 00 67 c6 69 73 51 ff 4a ec 29 cd ba ab f2 fb e3 46 7c
00 01 00 67 ffffffc6 69 73 51 ffffffff 4a ffffffec 29 ffffffcd ffffffba ffffffab fffffff2 fffffffb ffffffe3 46 7c

or

00 02 88 fa 7f 44 4f d5 d2 00 2d 29 4b 96 c3 4d c5 7d 29 7e
00 02 00 fffffffa 7f 44 4f ffffffd5 ffffffd2 00 2d 29 4b ffffff96 ffffffc3 4d ffffffc5 7d 29 7e

Why are there so many fffff for mesg_check?

Are there any potential reasons for this phenomenon?

like image 243
misteryes Avatar asked Apr 04 '13 23:04

misteryes


1 Answers

Here's a small program that illustrates the problem I think you might be having:

#include <stdio.h>
int main(void) {
    char arr[] = { 0, 16, 127, 128, 255 };
    for (int i = 0; i < sizeof arr; i ++) {
        printf(" %2x", arr[i]);
    }
    putchar('\n');
    return 0;
}

On my system (on which plain char is signed), I get this output:

  0 10 7f ffffff80 ffffffff

The value 255, when stored in a (signed) char, is stored as -1. In the printf call, it's promoted to (signed) int -- but the "%2x" format tells printf to treat it as an unsigned int, so it displays fffffffff.

Make sure that your mesg and mesg_check arrays are defined as arrays of unsigned char, not plain char.

UPDATE: Rereading this answer more than a year later, I realize it's not quite correct. Here's a program that works correctly on my system, and will almost certainly work on any reasonable system:

#include <stdio.h>
int main(void) {
    unsigned char arr[] = { 0, 16, 127, 128, 255 };
    for (int i = 0; i < sizeof arr; i ++) {
        printf(" %02x", arr[i]);
    }
    putchar('\n');
    return 0;
}

The output is:

 00 10 7f 80 ff

An argument of type unsigned char is promoted to (signed) int (assuming that int can hold all values of type unsigned char, i.e., INT_MAX >= UCHAR_MAX, which is the case on practically all systems). So the argument arr[i] is promoted to int, while the " %02x" format requires an argument of type unsigned int.

The C standard strongly implies, but doesn't quite state directly, that arguments of corresponding signed and unsigned types are interchangeable as long as they're within the range of both types -- which is the case here.

To be completely correct, you need to ensure that the argument is actually of type unsigned int:

printf("%02x", (unsigned)arr[i]);
like image 165
Keith Thompson Avatar answered Sep 30 '22 17:09

Keith Thompson