tags:

views:

262

answers:

4

Alright, I've cooked up some code to reverse hex characters around as part of a fun exercise I made up.

Here is what I have at the moment:

#include <stdio.h>  
int main() {  
    char a,b,c;  
    while (1) {  
        c = getchar();  
        if (!feof(stdin)) {  
            a = c % 16;  
            b = (c - a) / 16;  
            c = (a*16) + b;  
            putchar(c);  
        }else{break;}  
    }  
return 0;  
}  

It works well for most values. For example, 0xA0 becomes 0x0A etc...

However, it's not playing well with values beginning with 'F'.

0xF1 becomes 0x10
0xFF becomes 0xF0
etc...

Can somebody point me into the right direction?

+6  A: 

If char is signed on your system, then when the upper nibble of c is f, c is negative, and c%16 will give a negative result.

Neal Gafter
+5  A: 

You're using a signed (on your machine) data type. Switch it to unsigned and it should works properly.

akappa
You have got the solution, but note that `char` can be signed or unsigned depending on the implementation.
AraK
Indeed! Thanks! Now, since I'll never learn if I simply use it.You wouldn't mind explaining why signed-ness matters in char's? Or point to some sources?
Tangrs
You might think this a little too generic a link, but it's actually a very interesting article: http://en.wikipedia.org/wiki/Integer_(computer_science)
Steven Fisher
Note that you'll have to manually correct the link, as StackOverflow drops the ) from the end of it.
Steven Fisher
Tangrs: Evidently your signed `char` is 8 bits, and therefore can't store values like `0xFF` (or any value greater than 127 / `0x7F`). Values with the highest bit set are negative - for example, `0xF0` is actually -16. Your algorithm only works correctly on positive numbers.
caf
The signed-ness of char's should not matters, this is why it is a detail fixed by implementation and not by the language.If you're using C++, the correct datatype to use when dealing with raw data is byte, which is unsigned. In C or you explicitly state the signedness of char or (as others stated) just use bitwise operations, which aren't affected by signedness.
akappa
So, effectively, I can only store values up to 127, (on a signed char) otherwise, it's interpreted as a negative number right? Thus, by, making it unsigned, it'll assume they're all positive and make the maximum value 255 (which 0xFF is in range of) right?
Tangrs
right. (garbage to make the comment postable)
akappa
@akappa, there is no byte type in C++.
Matthew Flaschen
Watcom help files say they use unsigned chars as the default for quicker promotion to ints. (no sign extension necessary)
Arthur Kalliokoski
akallio: unsigned chars interoperate better with the standard library, anyway (eg. the comparison done by `strcmp` is done in terms of the characters interpreted as `unsigned char`).
caf
A: 

I dont know why someone is doing *, /, % operations while simple bitwise operations can do such things.

a = (c & 0x0F) << 4;
b = (c & 0xF0) >> 4;
c = a|b;

vrrathod
Quite the opposite. I don't know why would anyone use bitwise operations whnen normal human arithmetics will do the thing just as well.
AndreyT
Because for machines they are faster than the 'normal human arithmetics'
vrrathod
A: 

getchar and putchar return and take ints. Even better than this they use the value of the char cast to an unsigned char which means that for all valid characters putchar will return a positive value. This is needed for your algorithm as you use % and you would otherwise need to rely on implementation defined behaviour.

If you assign the value of getchar to an int then you can test whether the read failed for any reason (not just end-of-stream) by comparing against EOF. Using feof is then not necessary - it wasn't sufficient before.

E.g.

int main(void) {  
    int c;  
    while ((c = getchar()) != EOF) {  
        /* algorithm goes here */
        putchar(c);  
    }  
    return 0;  
}
Charles Bailey