简体   繁体   中英

How to manually convert decimal value to hexadecimal string in C?

nb I know that this question has been asked on StackOverflow before in a variety of different ways and circumstances, but the search for the answer I seek doesn't quite help my specific case. So while this initially looks like a duplicate of a question such as How can I convert an integer to a hexadecimal string in C? the answers given, are accurate, but not useful to me.

My question is how to convert a decimal integer, into a hexadecimal string, manually. I know there are some beat tricks with stdlib.h and printf, but this is a college task, and I need to do it manually (professor's orders). We are however, permitted to seek help.

Using the good old "divide by 16 and converting the remainder to hex and reverse the values" method of obtaining the hex string, but there must be a big bug in my code as it is not giving me back, for example "BC" for the decimal value "188".

It is assumed that the algorithm will NEVER need to find hex values for decimals larger than 256 (or FF). While the passing of parameters may not be optimal or desirable, it's what we've been told to use (although I am allowed to modify the getHexValue function, since I wrote that one myself).

This is what I have so far:

/* Function to get the hex character for a decimal (value) between
 * 0 and 16.  Invalid values are returned as -1.
 */
char getHexValue(int value) 
{
   if (value < 0) return -1;
   if (value > 16) return -1;
   if (value <= 9) return (char)value;
   value -= 10;
   return (char)('A' + value);
}


/* Function asciiToHexadecimal() converts a given character (inputChar) to
 * its hexadecimal (base 16) equivalent, stored as a string of
 * hexadecimal digits in hexString. This function will be used in menu
 * option 1.
 */
void asciiToHexadecimal(char inputChar, char *hexString)
{
   int i = 0;
   int remainders[2];
   int result = (int)inputChar;
   while (result) {
      remainders[i++] = result % 16;
      result /= (int)16;
   }
   int j = 0;
   for (i = 2; i >= 0; --i) {
      char c = getHexValue(remainders[i]);
      *(hexString + (j++)) = c;
   }
}

The char *hexString is the pointer to the string of characters which I need to output to the screen (eventually). The char inputChar parameter that I need to convert to hex (which is why I never need to convert values over 256).

If there is a better way to do this, which still uses the void asciiToHexadecimal(char inputChar, char *hexString) function, I am all ears, other than that, my debugging seems to indicate the values are ok, but the output comes out like \\377 instead of the expected hexadecimal alphanumeric representation.

Sorry if there are any terminology or other problems with the question itself (or with the code), I am still very new to the world of C.

Update: It just occurred to me that it might be relevant to post the way I am displaying the value in case its the printing, and not the conversion which is faulty. Here it is:

char* binaryString = (char*) malloc(8);
char* hexString = (char*) malloc(2);
asciiToBinary(*(asciiString + i), binaryString);
asciiToHexadecimal(*(asciiString + i), hexString);
printf("%6c%13s%9s\n", *(asciiString + i), binaryString, hexString);

(Everything in this code snip-pit works except for hexString )

 char getHexValue(int value) { if (value < 0) return -1; if (value > 16) return -1; if (value <= 9) return (char)value; value -= 10; return (char)('A' + value); } 

You might wish to print out the characters you get from calling this routine for every value you're interested in. :) ( printf(3) format %c .)

When you call getHexValue() with a number between 0 and 9, you return a number between 0 and 9, in the ASCII control-character range. When you call getHexValue() with a number between 10 and 15, you return a number between 65 and 75, in the ASCII letter range.

The sermon? Unit testing can save you hours of time if you write the tests about the same time you write the code.

Some people love writing the tests first. While I've never had the discipline to stick to this approach for long, knowing that you have to write tests will force you to write code that is easier to test. And code that is easier to test is less coupled (or 'more decoupled'), which usually leads to fewer bugs!

Write tests early and often. :)

Update : After you included your output code, I had to comment on this too :)

 char* binaryString = (char*) malloc(8); char* hexString = (char*) malloc(2); asciiToBinary(*(asciiString + i), binaryString); asciiToHexadecimal(*(asciiString + i), hexString); printf("%6c%13s%9s\\n", *(asciiString + i), binaryString, hexString); 

hexString has been allocated one byte too small to be a C-string -- you forgot to leave room for the ASCII NUL '\\0' character. If you were printing hexString by the %c format specifier, or building a larger string by using memcpy(3) , it might be fine, but your printf() call is treating hexString as a string.

In general, when you see a

char *foo = malloc(N);

call, be afraid -- the C idiom is

char *foo = malloc(N+1);

That +1 is your signal to others (and yourself, in two months) that you've left space for the NUL. If you hide that +1 in another calculation, you're missing an opportunity to memorize a pattern that can catch these bugs every time you read code. (Honestly, I found one of these through this exact pattern on SO just two days ago. :)

I made a librairy to make Hexadecimal / Decimal conversion without the use of stdio.h . Very simple to use :

char* dechex (int dec);

This will use calloc() to to return a pointer to an hexadecimal string, this way the quantity of memory used is optimized, so don't forget to use free()

Here the link on github : https://github.com/kevmuret/libhex/

Is the target purely hexadecimal, or shall the function be parametizable. If it's constrained to hex, why not exploit the fact, that a single hex digit encodes exactly four bits?

This is how I'd do it:

#include <stdlib.h>

#include <limits.h> /* implementation's CHAR_BIT */

#define INT_HEXSTRING_LENGTH (sizeof(int)*CHAR_BIT/4)
/* We define this helper array in case we run on an architecture
   with some crude, discontinous charset -- THEY EXIST! */
static char const HEXDIGITS[0x10] = 
    {'0', '1', '2', '3', '4', '5', '6', '7',
     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
void int_to_hexstring(int value, char result[INT_HEXSTRING_LENGTH+1])
{
    int i;
    result[INT_HEXSTRING_LENGTH] = '\0';

    for(i=INT_HEXSTRING_LENGTH-1; value; i--, value >>= 4) {
        int d  = value & 0xf;
        result[i] = HEXDIGITS[d];
    }

    for(;i>=0;i--){ result[i] = '0'; }
}
int main(int argc, char *argv[])
{
    char buf[INT_HEXSTRING_LENGTH+1];

    if(argc < 2)
        return -1;

    int_to_hexstring(atoi(argv[1]), buf);
    puts(buf);
    putchar('\n');

    return 0;
}
#include<stdio.h>

char* inttohex(int);
main()
{
    int i;
    char *c;
    printf("Enter the no.\n");
    scanf("%d",&i);
    c=inttohex(i);
    printf("c=%s",c);
}

char* inttohex(int i)
{
    int l1,l2,j=0,n;
    static char a[100],t;

    while(i!=0)
    {
    l1=i%16;
    if(l1>10)
    {
        a[j]=l1-10+'A';
    }

    else
        sprintf(a+j,"%d",l1);

    i=i/16;
    j++;
    }
    n=strlen(a);
    for(i=0;i<n/2;i++)
    {
        t=a[i];
        a[i]=a[n-i-1];
        a[n-i-1]=t;
    }

    //printf("string:%s",a);
    return a;
    //
}

In complement of the other good answers....

If the numbers represented by these hexadecimal or decimal character strings are huge (eg hundreds of digits), they won't fit in a long long (or whatever largest integral type your C implementation is providing). Then you'll need bignums . I would suggest not coding your own implementation (it is tricky to make an efficient one), but use an existing one like GMPlib

You're very close - make the following two small changes and it will be working well enough for you to finish it off:

(1) change:

if (value <= 9) return (char)value;

to:

if (value <= 9) return '0' + value;

(you need to convert the 0..9 value to a char, not just cast it).

(2) change:

void asciiToHexadecimal(char inputChar, char *hexString)

to:

void asciiToHexadecimal(unsigned char inputChar, char *hexString)

(inputChar was being treated as signed, which gave undesirable results with % ).

A couple of tips:

  • have getHexValue return '?' rather than -1 for invalid input (make debugging easier)

  • write a test harness for debugging, eg

     int main(void) { char hexString[256]; asciiToHexadecimal(166, hexString); printf("hexString = %s = %#x %#x %#x ...\\n", hexString, hexString[0], hexString[1], hexString[2]); return 0; } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM