3

So I am writing a very small and simple program which takes a number as input, converts it to hex, and prints it out two characters at a time.

For some numbers, it prints out ffffff in front of the output.

This is my code:

    //Convert the input to an unsigned int
unsigned int a = strtoul (argv[1], NULL, 0);
//Convert the unsigned int to a char pointer
char* c = (char*) &a;

//Print out the char two at a time
for(int i = 0; i < 4; i++){
    printf("%02x ", c[i]);
}

Most of the output is fine and looks like this:

./hex_int 1

01 00 00 00

But for some numbers the output looks like this:

./hex_int 100000

ffffffa0 ffffff86 01 00

If you remove all the f's the conversion is correct, but I cannot figure out why it is doing this only on some inputs.

Anyone have any ideas?

CiaPan
  • 9,381
  • 2
  • 21
  • 35
billg118
  • 561
  • 1
  • 5
  • 13
  • 1
    possible duplicate of [Why does printf not print out just one byte when printing hex?](http://stackoverflow.com/questions/3555791/why-does-printf-not-print-out-just-one-byte-when-printing-hex) – CB Bailey Aug 28 '13 at 20:45
  • Not the cause of your problem, but since `strtoul` returns an `unsigned long`, you should probably declare `a` to be `unsigned long` even though on your processor it may or may not be the same size. – lurker Aug 28 '13 at 20:47
  • @mbratch - that's a good idea for consistency's sake, but probably not strictly necessary. The conversion from `unsigned long` to `unsigned int` is well-defined. – Carl Norum Aug 28 '13 at 20:48
  • @CarlNorum indeed. I guess I'm just a little OCD... – lurker Aug 28 '13 at 20:49

4 Answers4

6

You're mismatching parameters and print formats. The default argument promotions cause your char parameter (c[i]) to be promoted to int, which sign extends (apparently your char is a signed type). Then you told printf to interpret that argument as unsigned int by using the %x format. Boom - undefined behaviour.

Use:

printf("%02x ", (unsigned int)(unsigned char)c[i]);

Instead.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • I also realized the problem can be solved (I think) by declaring c as an unsigned char* instead of just char*. Thanks for the quick response though. – billg118 Aug 28 '13 at 20:47
  • 1
    Using `unsigned char` will probably give you the right output, but it's still undefined behaviour. The argument promotion is still to undecorated `int`. – Carl Norum Aug 28 '13 at 20:48
  • The cast directly to `unsigned int` will avoid the undefined behaviour but you are still likely to get the `ffffff` "prefix" on negative `char` values. – CB Bailey Aug 28 '13 at 20:50
  • Ok I'm going to go with unsigned int then. Thanks guys! – billg118 Aug 28 '13 at 20:50
  • @CharlesBailey - that's probably true. Let me fix that up. – Carl Norum Aug 28 '13 at 20:51
  • @CharlesBailey - You're correct. I tried using (unsigned int) and I am still getting the f's on some values. I think I am going to stick with making c an unsigned char. That seems to work correctly. – billg118 Aug 28 '13 at 20:53
  • @billg118 - you should still use the `unsigned int`. I've edited my answer to be correct now; you can remove the `unsigned char` cast if you change the type of `c`. – Carl Norum Aug 28 '13 at 20:54
  • @CarlNorum Thanks this seems to work fine. I now have another error though. When I input the maximum value for an unsigned long int (4,294,967,295) it should output FF FF FF FF but instead it outputs FD FF FF 7F. Any idea why it would be doing this? – billg118 Aug 28 '13 at 21:15
  • @CarlNorum Yeah. It is strange I sent it to my buddy for him to try and it works correctly for him. Not sure what is going on here. – billg118 Aug 28 '13 at 21:25
0

char is, by default, signed on your system. Moving an int into it makes your compiler think you want to use the highest bit as sign bit on operations that needs to be cast to an int. And printing it as a hex number is one.

Make the char pointer c an unsigned char * and the problem will go away.

If Carl is right with his comment (I'm going to check), use this fail-safe method instead:

printf("%02x ", c[i] & 0xff);
Jongware
  • 22,200
  • 8
  • 54
  • 100
  • Strictly speaking, using `unsigned char *` still causes undefined behaviour in the print statement. – Carl Norum Aug 28 '13 at 20:50
  • The change you made didn't fix that either. The UB is caused by the default argument promotion turning that value into an `int` and then using `%x` to print an `unsigned int`. The same happens with your `&`. – Carl Norum Aug 28 '13 at 20:53
  • So it'd need `printf("%02x ", ((int)c[i]) & 0xff);`? (Probably too many parentheses, but now I'm going for broke!) – Jongware Aug 28 '13 at 20:59
  • No, you need to pass an `unsigned int` to match the `%x`. Use `printf("%02x ", (unsigned int)c[i]);`, assuming `c` is an `unsigned char *`. – Carl Norum Aug 28 '13 at 20:59
  • @Carl: it works on gcc 4.2.1 as I initially described. Without looking at the code of `printf`: I am at a loss at your description of 'default argument promotion'. Even though `c` is promoted to int at *some* point, this will *surely* honor its original unsignednessness? – Jongware Aug 28 '13 at 21:39
  • 1
    It most certainly does not. "If an `int` can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an `int`..." A `signed int` can represent all of the values of an `unsigned char` (assuming `sizeof(int)` > 1, that is). Undefined behaviour is still undefined, even if it happens to give apparently correct results. – Carl Norum Aug 28 '13 at 23:14
-1

I where doing this for a while and i realize, you can see the exe image in a process, use a debuger, the code is all right, but i cant for the moment to pass this machine code to assembler, but well, with a pointer all is possible

include stdio.h

include windows.h

int main ()

{

int i=0;

char * p = (char *)0x400000;

for(int i = 0; i < 20; i++)

{

    printf("%p %02x \n",p+i, (unsigned int)(unsigned char)*(p+i));
}

}
Panagiotis Koursaris
  • 3,794
  • 4
  • 23
  • 46
dbg
  • 1
  • 1
    How is this even remotely relevant to OP's question? P.S.1. The `(unsigned int)` cast is unnecessary. P.S.2. Memory address `0x400000` is not guaranteed to be readable at all. Yes, it may usually be in Windows x86 (since you mentioned `windows.h`) but note that the question was tagged as just `C` without reference to any particular OS or platform. – dxiv Jul 05 '16 at 05:46
-2

Well, the windows.h was added to use some system calls, i omit those in the example, because is not necesary to use those in the code below, about unsigned, yes it can be ommited, cause char is always >0, about the address, as you said before, 0400000 is the header of the exe, "mz" header in this case, but the code of the dll of the process could be 7c911000, and the header of the dll another address, and so on.., this infomation is inside the exe file and must be readed to have and idea of where the loaded image is load in principal memory, but when you have only one process, is you have more, you must use system calls to know where is the second process, if one address is not readable, just read de exe in a notepad, that address was only an example

dbg
  • 1
  • 1
  • 1
    Please read the help page before answering questions. This is basically a comment on your answer instead of an answer. Also your other answer isn't in the scope of the question. – rfkortekaas Jul 05 '16 at 21:05
  • what?, did you read the title of the thread?, printing in hex etc, that's the main theme here, billg118 open this thread, i am posting and altenative code than carl, i am not doing a paralel dialog box or wathever, my answer is in the scope of the question bacause of the code i`ve posted, instead of talking about questions, talking about main thread is in scope in this forum, or not? – dbg Jul 06 '16 at 17:01