1

Are there any possibilities to put "%X" in write() function to get hex number of ascii characters?

Like in printf("Hex number of .. : %X").

Thank you in advance!

13
  • Maybe sprintf() it into a string first? Commented Jul 27, 2021 at 15:44
  • I cannot use sprintf() in code( Commented Jul 27, 2021 at 15:44
  • Does this answer your question? Printing hexadecimal characters in C Commented Jul 27, 2021 at 15:45
  • @Björn Do any of the answers there show how to do it without built-in formatting functions? Commented Jul 27, 2021 at 15:46
  • 2
    Create an array with all the hex digits. Then use bit masking and shifting to extract each 4-bit field of the number, and use them as indexes into the array. Commented Jul 27, 2021 at 15:48

3 Answers 3

1

Short answer

Since write does not take format string and additional arguments, you have to either use printf, or implement your own function that takes an integer and translates it into the hex representation.

Below I describe how to write your own %X-like output and how it works.

Converting characters to hex characters

You can convert an integer (and therefore the hex code of a character) into a hex string by dividing the number by 16 and taking the modulo of it repeatedly.

For example, let's consider the value of 'A', which is 41 in hex. The remainder of division of that number by 16 is equal to the value of its last digit -- 1. Then if we divide the value 0x41 by 16, we get the same number without the last digit -- 0x4.

One can think of a step of such iteration:

int valueToConvert = 'A';
int lastHexDigit = valueToConvert % 16; // get the value of the last hex digit
valueToConvert = valueToConvert / 16;   // save the remainder of the number

That gets us the value of the last hex digit (as integer).

Now we want to convert the integer value of this digit to char, i.e. converting the value 0 to '0'. Since characters in ASCII are stored consecutively we can get the value of digit by adding '0' to the integer value we wish to convert.

char charDigit = '0' + digitValue;

The code snippet above will work only for digitValue less or equal to 9. For digits A through F we need to add a condition and if digitValue is bigger than 9 we are going to (using the same logic), subtract 10 from digitValue and then add 'A' to it. Since alphabetical characters are also consecutive in ASCII codes we can freely use digitValue-10 as an offset from 'A' character.

char charDigit;
if (digitValue < 10) {
  charDigit = '0' + digitValue;
}
else {
  charDigit = 'A' + (digitValue-10);
}

So if digitValue is 0xA (10), then digitValue-10 is 0, and adding 0 to 'A' just leaves us with 'A'.

Converting an integer to hex string representation

By taking modulo of division by 16, we get the least significant (right most) hexadecimal digit. However printing the string is done from left to right, not from right to left.

So in order to print a string representation we would need to have some sort of buffer to store all of our right most characters. Just remember this -- no int value will have more than 8 hexadecimal digits, so we can freely allocate an array of 8 chars.

char digits[8];
int digitIndex = 8;

The digitIndex will keep track of which array slot we write in. Note that it is set to 8, not 7, this is for a reason I will explain later.

Now let us put back the code from before -- we will use a do/while to "put the last digit into the last spot of the array until the remainder is zero".

int valueToConvert = ...; // leaving the declaration here for clarity

do {
  // Get the value of the last digit
  int lastDigit = valueToConvert % 16;

  // Convert the last digit to char
  char charDigit;
  if (lastDigit < 10) {
    charDigit = '0' + lastDigit;
  }
  else {
    charDigit = 'A' + (lastDigit-10);
  }

  // Put the last digit into the array
  digitIndex -= 1;
  digits[digitIndex] = charDigit;

  valueToConvert /= 16;
} while(valueToConvert != 0);

This should produce the hex value corresponding to a given int, assuming valueToConvert is not negative.

Now let me explain why I'm subtracting the index first: we will use the value of digits+digitIndex (which is a char *) as the starting point of our array of digits. If I subtract first and then put the digit at that spot, that guarantees that when the loop exits, digitIndex is over the first digit, which is very convenient.

Now let us get the length of the array:

unsigned count = 8 - digitIndex;

Which is simply the size of our buffer minus the index of the first digit of the number in the array.

Finally

After converting the value to our digit array we simply call write:

write(handle, digits+digitIndex, count);

Full picture:

void write_hex_of_int(int handle, int number)
{
  char digits[8];
  int digitIndex = 8;

  // Fill the `digits` array with the digits of the number
  int valueToConvert = number;
  do {
    // Get the value of the last digit
    int lastDigit = valueToConvert % 16;

    // Convert the last digit to char
    char charDigit;
    if (lastDigit < 10) {
      charDigit = '0' + lastDigit;
    }
    else {
      charDigit = 'A' + (lastDigit-10);
    }

    // Put the last digit into the array
    digitIndex -= 1;
    digits[digitIndex] = charDigit;

    valueToConvert /= 16;
  } while(valueToConvert != 0);

  // Get the actual width of the number and print it.
  unsigned count = 8 - digitIndex;
  write(handle, digits+digitIndex, count);
}
Sign up to request clarification or add additional context in comments.

Comments

1

Are there any possibilities to put "%X" in write() function to get hex number of ascii characters?

No. The %X is a specific characteristic of the printf family of formatted output functions. (The 'f' is mnemonic for "formatted".) write() performs raw output -- exactly the bytes you specify. If you want to use write() then you will have to perform the formatting yourself, which I suppose is a large part of the point of the assignment.

Comments

1

You need to write your own function.

char toHexDigit(int x)
{
    char result;
    if(x > 15) x = 0;
    if((x >= 0 && x < 10)) result = '0' + x;
    else result = 'A' + x - 10;

    return result;
}

char *tohex(unsigned x)
{
    static char buff[sizeof(x)*2];

    for(ssize_t i = 0; i < sizeof(x) * 2; i++)
    {
        int shift = (sizeof(x) * 2 - i - 1) * 4;
        buff[i] = toHexDigit((x & (0xf << shift)) >> shift);
    }
    return buff;
}

int main(void)
{
    write(1, tohex(0xD2A45678), sizeof(unsigned)*2);
}

https://godbolt.org/z/zveYazchj

8 Comments

Perhaps worth pointing out that while tohex returns a char *, it does not return a C string.
write may do partial writes. You should normally call write in a loop.
It is also worth pointing out that tohex is not thread safe. IMHO it is bad practice to use static as a poor mans "return array", It is better to let the caller provide the array when the size is known, or use malloc when size is not known.
@SteveSummit it does not have to return C string as write does not take C strings as a parameter.
I am not a fan of this answer. Yes it answers the question but SO isn't a code service site.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.