18

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?

9
  • 2
    What do mesg and mesg_check look like? Commented Apr 4, 2013 at 23:41
  • 1
    would mesg be a char* or char[] by any chance? Commented Apr 4, 2013 at 23:42
  • 1
    Try to put a space in the printf specifier. Ie, "%2.2x " You are getting many number put together and negatives are being sign extended. Commented Apr 4, 2013 at 23:56
  • 1
    You accepted an answer, but you still haven't shown us how mesg and mesg_check are defined -- not how you initialize them, but what their declarations look like. Showing us that could be helpful to future readers of this question. Commented Apr 5, 2013 at 14:48
  • 1
    Possible duplicate of Why does printf not print out just one byte when printing hex? Commented Oct 11, 2017 at 6:51

2 Answers 2

27

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]);
Sign up to request clarification or add additional context in comments.

8 Comments

Can't he just use a width and precision like "%2.2x" and then it doesn't matter if it is signed or not? I guess it is more efficient to change the sign.
ah, mesg is from recvfrom(), which is of type void*, so how can I change the bytes to unsigned char?
+1 thats indeed what's happening, but the easiest way out is to just mask off all the rubbish, like printf(" %2x", arr[i] & 0xFF);
I tried something like printf("%2x", *((u_char*)(mesg+i)));it is still wrong, here you arr[i] is mesg or mesg_check ?
@misteryes: The real question is, how are mesg and mesg_check defined? Presumably you defined them yourself (in code you haven't yet shown us). If you're dealing with raw byte data, unsigned char is a better choice than plain char (for this and other reasons); plain char is for character data. You can pass an unsigned char* as the 2nd argument to recvfrom(). And if you're dumping data in hex, then "%02x" typically makes more sense; it prints values less than 0x10 with a leading 0.
|
-1

Yes, always print the string in hexadecimal format as:

for(i=0; till string length; i++)
    printf("%02X", (unsigned char)str[i]);

You will get an error when you try to print the whole string in one go and when printing the hexadecimal string character by character which is using 'unsigned char' if the string is in format other than 'unsigned char'.

1 Comment

That's not code, that's pseudo code. Please provide a complete example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.