user1812746
user1812746

Reputation: 11

Split up two byte char into two single byte chars

I have a char of value say 0xB3, and I need to split this into two separate char's. So X = 0xB and Y = 0x3. I've tried the following code:

int main ()
{
    char addr = 0xB3;
    char *p = &addr;

    printf ("%c, %c\n", p[0], p[1]);          //This prints ?, Y
    printf ("%X, %X\n", p[0], p[1]);          //This prints FFFFFFB3, 59

    return 0;
}

Just to clarify, I need to take any 2 byte char of value 00 to FF and split the first and second byte into separate char's. Thanks.

Upvotes: 0

Views: 7845

Answers (4)

YeaTheMen
YeaTheMen

Reputation: 1083

Ok so your trying to split 0xB3 into 0xB and 0x3, Just for future reference don't say 'byte chars', The 2 parts of a byte are commonly known as 'Nibbles', a byte is made up of 2 nibbles (which are made up of 4 bits). If you didn't know, char refers to 1 byte.

So heres the problems with your code:

char addr = 0xB3;  <---- Creates single byte with value 0xB3 - Good
char *p = &addr;   <---- Creates pointer pointing to 0xB3 - Good

printf ("%c, %c\n", p[0], p[1]); <---- p[0], p[1] - Bad
printf ("%X, %X\n", p[0], p[1]); <---- p[0], p[1] - Bad

Ok so when your referring to p[0] and p[1] your telling your system that the pointer p is pointing to an array of chars (p[0] would refer to 0xB3 but p[1] would be going to the next byte in memory)

Example : This is something your system memory would look like (But with 8 byte pointers)

     Integer Values Area              Pointers Area
0x01 0x02 0x03 0x04 0x05 0x06    0x12 0x13 0x14 0x15 0x16
-----------------------------    ------------------------
.... .... 0xB3 0x59 .... ....    .... .... 0x03 .... ....
-----------------------------    ------------------------
           ^    ^                           ^
          addr  |                           p (example pointer pointing to example address 0x03)
             Random number                    (Pointers are normally 8 Bytes but)
             showing up in p[1]               (But In this example I used single bytes)

So when you tell your system to get p[0] or *p (these would do the same thing) it will go to the address (eg. 0x03) and get one byte (because its a char) in this case 0xB3. But when you try p[1] or *(p+1) That will go to the address (eg. 0x03) skip the first char and get the next one giving us 0x59 which would be there for some other variable.

Ok so we've got that out of the way so how do you get the nibbles?

A problem with getting the nibble is that you generally can't just have half a byte a put variable, theres no type that supports just 4 bits. When you print with %x/%X it will only show the nibbles up to the last non-zero number eg. = 0x00230242 would only show 230242 but if you do something like

%2lX would show 2 full bytes (including the zeros) %4lX would show 4 full bytes (including the zeros)

So it is pretty pointless trying to get individual nibbles but if you want way to do something like then do:

char addr = 0x3B;
char addr1 = ((addr >> 4) & 0x0F);
char addr2 = ((addr >> 0) & 0x0F);

Upvotes: 0

Mike
Mike

Reputation: 49463

There's quite a few problems here, let's take a look at your code:

int main ()
{
    char addr = 0xB3;  <-- you're asigning 0xB3 in hex, which is (179 in dec) to addr
    char *p = &addr;   <-- you're assigning a pointer to point to addr

If addr were unsigned, it would now be set to 179, the extended ASCII of │ ( Box drawing character )

A char value can be -127 to +127 if it's signed, or 0 to 255 if it's unsigned. Here (according to your output) it's signed, so you're overflowing the char with that assignment.

printf ("%c, %c\n", p[0], p[1]); <-- print the char value of what p is pointing to
                                     also, do some UB
printf ("%X, %X\n", p[0], p[1]); <-- print the hex value of  what p is pointing to
                                     also, do some UB

So the second part of your code here prints the char value of your overflowed addr var, which happens to print '?' for you. The hex value of addr is FFFFFFB3 indicating you have a negitive value (upper most bit is the signed bit).

This: p[0] is really an "add and deference" operator. Meaning that we're going to take the address of p, add 0 to it, then deference and look at the result:

p ---------+
           V
       ------------------------------------------
      | ptr(0xB3) |    ?      |     ?     | ... |
      -------------------------------------------
       0xbfd56c2b  0xbfd56c2C  0xbfd56c2d   ...      

When you do p[1] this goes one char or one byte past ptr and gives you that result. What's there? Don't know. That's out of your scope:

p+1 -------------------+
                       V
       ------------------------------------------
      | ptr(0xB3) |    ?      |     ?     | ... |
      -------------------------------------------
       0xbfd56c2b  0xbfd56c2C  0xbfd56c2d   ...   

Y's ASCII value (in hex) is 0x59, so behind your pointer in memory was a Y. But it could have been anything, what is was going to do was undefined. A correct way to do this would be:

int main ()
{
    unsigned char addr = 0xB3;
    char low = addr & 0x0F;
    char high = (addr >> 4) & 0x0F;

    printf("%#x becomes %#x and %#x\n", addr, high, low);

    return 0;
}

This works via:

    0xB3  =>  1011 0011        0xB3 >> 4 =   0000 1011
            & 0000 1111                    & 0000 1111
            ------------                  -------------
              0000 0011 => 3 low             0000 1011 => B high

Upvotes: 1

Jack
Jack

Reputation: 133609

Why do you need to pass by a pointer? just take the 4 relevant bits and shift the most significative when needed:

char lower = value & 0x0F;
char higher = (value >> 4) & 0x0F;

Then 0xB3 is a single byte, not two bytes. Since a hex digit can have 16 values two digits can store 16*16 = 256 values, which is how much you can store in a byte.

Upvotes: 0

Fred Foo
Fred Foo

Reputation: 363737

Straight from the Wikipedia:

#define HI_NIBBLE(b) (((b) >> 4) & 0x0F)
#define LO_NIBBLE(b) ((b) & 0x0F)

So HI_NIBBLE(addr) would be 0xB. However, 0x00 through 0xFF are not "double bytes". They're single-byte values. A single hex digit can take on 16 bytes, while a byte can take on 256 = 16² of them, so you need two hex digits to represent arbitrary byte values.

Upvotes: 5

Related Questions