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!

3 Answers3

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
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

0___________
  • 60,014
  • 4
  • 34
  • 74
  • Perhaps worth pointing out that while `tohex` returns a `char *`, it does *not* return a C string. – Steve Summit Jul 27 '21 at 17:34
  • `write` may do partial writes. You should normally call `write` in a loop. – HAL9000 Jul 27 '21 at 17:35
  • 1
    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. – HAL9000 Jul 27 '21 at 17:41
  • @SteveSummit it does not have to return C string as `write` does not take C strings as a parameter. – 0___________ Jul 27 '21 at 17:52
  • @HAL9000 it is an example and thank you for your wisdom. – 0___________ Jul 27 '21 at 17:52
  • Yes, but it is a buggy example on how to use `write`. Remember that someone that has problems with turning bytes into a hex representation, may not know how to call `write` correctly. And the question did actually ask for help about using `write`. – HAL9000 Jul 27 '21 at 17:57
  • Oh, and by showing the correct use of `write`, maybe beginners would understand that `fprintf` and other `FILE *` based functions exist for a reason.... – HAL9000 Jul 27 '21 at 18:03
  • 1
    I am not a fan of this answer. Yes it answers the question but SO isn't a code service site. – 12431234123412341234123 Jul 27 '21 at 18:39
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);
}
bumbread
  • 460
  • 2
  • 11