2
votes

I got a problem that says: Form a character array based on an unsigned int. Array will represent that int in hexadecimal notation. Do this using bitwise operators.

So, my ideas is the following: I create a mask that has 1's for its 4 lowest value bits. I push the bits of the given int by 4 to the right and use & on that int and mask. I repeat until (int != 0). My question is: when I get individual hex digits (packs of 4 bits), how do I convert them to a char? For example, I get:

x & mask = 1101(2) = 13(10) = D(16)

Is there a function to convert an int to hex representation, or do I have to use brute force with switch statement or whatever else?

I almost forgot, I am doing this in C :)

Here is what I mean:

#include <stdio.h>
#include <stdlib.h>

#define BLOCK 4

    int main() {
        unsigned int x, y, i, mask;
        char a[4];

        printf("Enter a positive number: ");
        scanf("%u", &x);
        for (i = sizeof(usnsigned int), mask = ~(~0 << 4); x; i--, x >>= BLOCK) {
            y = x & mask;
            a[i] = FICTIVE_NUM_TO_HEX_DIGIT(y);
        }

        print_array(a);

        return EXIT_SUCCESS;
    }
5
Take a look at sprintf - Kninnug
char hex_digits[] = "0123456789ABCDEF"; string_rep[i] = hex_digits[x & mask]; - Daniel Fischer
@DanielFischer: Can you make that comment an answer? - Brendan
#define FICTIVE_NUM_TO_HEX_DIGIT(n) "0123456789ABCDEF"[n] - BLUEPIXY

5 Answers

1
votes

You are almost there. The simplest method to convert an integer in the range from 0 to 15 to a hexadecimal digit is to use a lookup table,

char hex_digits[] = "0123456789ABCDEF";

and index into that,

a[i] = hex_digits[y];

in your code.

Remarks:

char a[4];

is probably too small. One hexadecimal digit corresponds to four bits, so with CHAR_BIT == 8, you need up to 2*sizeof(unsigned) chars to represent the number, generally, (CHAR_BIT * sizeof(unsigned int) + 3) / 4. Depending on what print_array does, you may need to 0-terminate a.

for (i = sizeof(usnsigned int), mask = ~(~0 << 4); x; i--, x >>= BLOCK)

initialising i to sizeof(unsigned int) skips the most significant bits, i should be initialised to the last valid index into a (except for possibly the 0-terminator, then the penultimate valid index).

The mask can more simply be defined as mask = 0xF, that has the added benefit of not invoking undefined behaviour, which

mask = ~(~0 << 4)

probably does. 0 is an int, and thus ~0 is one too. On two's complement machines (that is almost everything nowadays), the value is -1, and shifting negative integers left is undefined behaviour.

0
votes
char buffer[10] = {0};
int h = 17;
sprintf(buffer, "%02X", h);
0
votes

Try something like this:

char hex_digits[] = "0123456789ABCDEF";

for (i = 0; i < ((sizeof(unsigned int) * CHAR_BIT + 3) / 4); i++) {
    digit = (x >> (sizeof(unsigned int) * CHAR_BIT - 4)) & 0x0F;
    x = x << 4;
    a[i] = hex_digits[digit];
}
0
votes

Ok, this is where I got:

#include <stdio.h>
#include <stdlib.h>

#define BLOCK 4

void printArray(char*, int);

int main() {
    unsigned int x, mask;
    int size = sizeof(unsigned int) * 2, i;
    char a[size], hexDigits[] = "0123456789ABCDEF";

    for (i = 0; i < size; i++)
        a[i] = 0;

    printf("Enter a positive number: ");
    scanf("%u", &x);
    for (i = size - 1, mask = ~(~0 << 4); x; i--, x >>= BLOCK) {
        a[i] = hexDigits[x & mask];
    }

    printArray(a, size);

    return EXIT_SUCCESS;
}

void printArray(char a[], int n) {
    int i;

    for (i = 0; i < n; i++)
        printf("%c", a[i]);

    putchar('\n');
}

I have compiled, it runs and it does the job correctly. I don't know... Should I be worried that this problem was a bit hard for me? At faculty, during exams, we must write our code by hand, on a piece of paper... I don't imagine I would have done this right. Is there a better (less complicated) way to do this problem? Thank you all for help :)

0
votes

I would consider the impact of potential padding bits when shifting, as shifting by anything equal to or greater than the number of value bits that exist in an integer type is undefined behaviour.

Perhaps you could terminate the string first using: array[--size] = '\0';, write the smallest nibble (hex digit) using array[--size] = "0123456789ABCDEF"[value & 0x0f], move onto the next nibble using: value >>= 4, and repeat while value > 0. When you're done, return array + size or &array[size] so that the caller knows where the hex sequence begins.