1

I have char byte[0] = '1' (H'0x31)and byte[1] = 'C'(H'0x43)

I am using one more buffer to more buff char hex_buff[0] .i want to have hex content in this hex_buff[0] = 0x1C (i.e combination of byte[0] and byte[1])

I was using below code but i realized that my code is valid for the hex values 0-9 only

char s_nibble1 = (byte[0]<< 4)& 0xf0;

char s_nibble2 =  byte[1]& 0x0f;

hex_buff[0] = s_nibble1 | s_nibble2;// here i want to have 0x1C instead of 0x13

User
  • 619
  • 1
  • 9
  • 24
  • I think an `if else` clause would work wonders here. – Mark Ransom Sep 09 '14 at 15:43
  • Converting an ASCII digit to hex is as straightforward as you already have. Converting `A` to `F` not so much -- you mask off the lowest 4 bits and get `0` to `5`. There must be some system behind this ... – Jongware Sep 09 '14 at 15:49
  • @Jongware you don't get 0 to 5, you get 1 to 6. But quick - how do you convert the range 1 to 6 into 10 to 15? – Mark Ransom Sep 09 '14 at 15:53
  • OT: `char hex_buff[0]` is a quite useless statement. It declares the array `hex_buff` to hold `0` elements. – alk Sep 09 '14 at 16:25
  • @Mark: sorry, you're right (`A`=`0x41`). Then add 9 (which is where aforementioned `if` comes into play). Me, I'm partial to `"0123456789ABCDEF"[byte & 15]`, which is both straightforward and encoding agnostic. – Jongware Sep 09 '14 at 17:30

4 Answers4

2

What keeps you from using strtol()?

char bytes[] = "1C";
char buff[1];
buff[0] = strtol(bytes, NULL, 16);  /* Sets buff[0] to 0x1c aka 28. */

To add this as per chux's comment: strtol() only operates on 0-terminated character arrays. Which does not necessarily needs to be the case for the OP's question.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
alk
  • 69,737
  • 10
  • 105
  • 255
1

You are trying to get the nibble by masking out the bits of character code, rather than subtracting the actual value. This is not going to work, because the range is disconnected: there is a gap between [0..9] and [A-F] in the encoding, so masking is going to fail.

You can fix this by adding a small helper function, and using it twice in your code:

int hexDigit(char c) {
    c = toupper(c); // Allow mixed-case letters
    switch(c) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9': return c-'0';
        case 'A':
        case 'B':
        case 'C':
        case 'D':
        case 'E':
        case 'F': return c-'A'+10;
        default: // Report an error
    }
    return -1;
}

Now you can code your conversion like this:

int val = (hexDigit(byte[0]) << 4) | hexDigit(byte[1]);
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    If you're going to the trouble of listing each character individually, you could have it directly return the digit value instead of doing math. – Mark Ransom Sep 09 '14 at 15:55
  • @MarkRansom That is certainly true. I think the version with the math is somewhat more readable, although it makes an assumption that the two regions (i.e. digits and letters) are contiguous in the encoding. – Sergey Kalinichenko Sep 09 '14 at 15:59
  • @dasblinkenlight: 0-9 are guaranteed to be contiguous, and _I think_ A-F are as well, though no other ranges. Presumably for this purpose. – Mooing Duck Sep 09 '14 at 16:39
  • @MooingDuck Right, that's why I am comfortable with the code that makes this assumption :) – Sergey Kalinichenko Sep 09 '14 at 16:43
  • @Mooing DuckAs OP requests "ASCII(Hex) number", thus safe to assume the nibble characters are also ASCII and `'A'` - `'F'` is continuous. Otherwise, C does not specify `'A'` - `'F'` as continuous. Same for `'a'` - `'z'` – chux - Reinstate Monica Sep 09 '14 at 16:50
  • Confirmed, A-F are not guaranteed to be contiguous. Maybe I read somewhere that they simply _are_ contiguous in all widespread encodings. I can't find any where A-I are not contiguous at least. – Mooing Duck Sep 09 '14 at 17:02
1

A possible way to do it, without dependencies with other character manipulation functions:

char hex2byte(char *hs)
{
    char b = 0;
    char nibbles[2];
    int i;

    for (i = 0; i < 2; i++) {
        if ((hs[i] >= '0') && (hs[i] <= '9')) 
            nibbles[i] = hs[i]-'0';
        else if ((hs[i] >= 'A') && (hs[i] <= 'F')) 
            nibbles[i] = (hs[i]-'A')+10;
        else if ((hs[i] >= 'a') && (hs[i] <= 'f')) 
            nibbles[i] = (hs[i]-'a')+10;
        else 
            return 0;
    }

    b = (nibbles[0] << 4) | nibbles[1];
    return b;
}

For example: hex2byte("a1") returns the byte 0xa1.

In your case, you should call the function as: hex_buff[0] = hex2byte(byte).

Claudi
  • 5,224
  • 17
  • 30
1

It looks like you are trying to convert ASCII hex into internal representation.

There are many ways to do this, but the one I use most often for each nibble is:

int nibval(unsigned short x)
{
    if  (('0' <= x) && ('9' >= x))
    {
        return  x - '0';
    }
    if  (('a' <= x) && ('f' >= x))
    {
        return  x - ('a' - 10);
    }
    if  (('A' <= x) && ('F' >= x))
    {
        return  x - ('A' - 10);
    }

    //  Invalid input
    return  -1;
}

This uses an unsigned int parameter so that it will work for single byte characters as well as wchar_t characters.

Logicrat
  • 4,438
  • 16
  • 22