Displaying 64bit Numbers

N

Nathan Waddington

Hello Everyone,

My program receives a string representation of a 64bit hex number that
needs to be displayed as the decimal number it represents. The compiler
that is being used is Dynamic C and (alas) it does not support 64bit
numbers.

So far i have been able to take the least significant 4 bytes and
convert them correctly, but when i try to take the most significant 4
bytes i am unable to convert them correctly. Below are the 3 functions
that i am using, the third is the one that i am having trouble with
(the others are here as a reference).

Can anyone provide any suggestions as to how i can deal with these?

here is some sample output:

original: 2EEA9
expected: 00192169
actual: 00192169

original: 5F5E0FF
expected: 99999999
actual: 99999999

original: 1C6BF526340003
expected: 8000000000000003
actual: 640942083

Thanks in advance.

#include <stdio.h>
#include <string.h>
#include <ctype.h>

unsigned int UTIL_HexCharToInt(char);
unsigned long UTIL_HexStrToLong(char *, int);
void DecodeAcct(char *, char *);

unsigned int UTIL_HexCharToInt(char c)
{
auto unsigned int lResult;

lResult = 0L;

if (isxdigit(c)) {
if (c <= '9') {
lResult = (unsigned int) (c - '0');
} else {
c = toupper(c);
lResult = (unsigned int) (c - 'A') + 10;
}
}

return (lResult);
}

unsigned long UTIL_HexStrToLong(char *szStr, int len)
{
auto unsigned long lResult, lTmp, lPwr;
auto int i;
auto char *pStr;

// work from the end of the buffer
pStr = &szStr[len - 1];

// convert the hex string to long
for (i = 0, lResult = 0L; i < len; i++, pStr--) {
// work out power of the hex digit
switch (i) {
case 0:
lPwr = 1L;
break;
case 1:
lPwr = 16L;
break;
default:
lPwr = lPwr * 16L;
break;
}

// convert the hex character to long
lTmp = (unsigned long) UTIL_HexCharToInt(*pStr);
if (lTmp) {
lResult += lTmp * lPwr;
}
}

// return hex string in unsigned long
return (lResult);
}

void DecodeAcct(char *In, char *Out)
{
#define OVERFLOW 8
auto char overflow[9], temp[9];
auto int i, diff;
auto unsigned long int ln;

if (strlen(In) >= OVERFLOW+10) {
ln = 0;
diff = strlen(In) - OVERFLOW;
memset(overflow, 0, sizeof(overflow));

/* move most significant bytes into overflow buffer */
for (i = 0; i < diff; i++) {
overflow = In;
}

/* remove extra from original string */
for (i = 0; In != 0 && i <= strlen(In); i++) {
In = In[i + diff];
}
ln = UTIL_HexStrToLong(overflow, strlen(overflow));
sprintf(Out, "%lu", ln);
}

ln = 0;
memset(temp, 0, sizeof(temp));
ln = UTIL_HexStrToLong(In, strlen(In));

sprintf(temp, "%08lu", ln);
strcat(Out, temp);
}
 
N

Nathan Waddington

Sorry, wanted to make a correction to the Function:
> if (strlen(In) >= OVERFLOW+10) { should read:
> if (strlen(In) >= OVERFLOW) {


Nathan said:
void DecodeAcct(char *In, char *Out)
{
#define OVERFLOW 8
auto char overflow[9], temp[9];
auto int i, diff;
auto unsigned long int ln;

if (strlen(In) >= OVERFLOW+10) {
ln = 0;
diff = strlen(In) - OVERFLOW;
memset(overflow, 0, sizeof(overflow));

/* move most significant bytes into overflow buffer */
for (i = 0; i < diff; i++) {
overflow = In;
}

/* remove extra from original string */
for (i = 0; In != 0 && i <= strlen(In); i++) {
In = In[i + diff];
}
ln = UTIL_HexStrToLong(overflow, strlen(overflow));
sprintf(Out, "%lu", ln);
}

ln = 0;
memset(temp, 0, sizeof(temp));
ln = UTIL_HexStrToLong(In, strlen(In));

sprintf(temp, "%08lu", ln);
strcat(Out, temp);
}
 
M

Malcolm

Nathan Waddington said:
My program receives a string representation of a 64bit hex number that
needs to be displayed as the decimal number it represents. The compiler
that is being used is Dynamic C and (alas) it does not support 64bit
numbers.
I found this surprisingly hard, when you can't hold the number in
intermediate binary.

Here's what I came up with (tested, but not exhaustively).

/*
convenience function to duplicate a string
*/
char *mystrdup(const char *str)
{
char *answer;

answer = malloc(strlen(str) + 1);

/* you will have to decide your out of memory strategy */
if(!answer)
exit(EXIT_FAILURE);

strcpy(answer, str);
return answer;
}

/*
convert a hex digit to binary
*/
int hexval(char hex)
{
static char *digits = "0123456789ABCDEF";
char *pos;

hex = toupper(hex);
pos = strchr(digits, hex);
assert(pos);

return pos - digits;
}

/*
convert a binary number 0-16 to a hex digit
*/
char bintohex(int val)
{
static char *digits = "0123456789ABCDEF";

assert(val >= 0 && val < 16);
return digits[val];
}

/*
divide a hex number by ten, in hexadecimal
out - return pointer for answer (in hex);
hex - input number
returns - the remainder
*/
int divideby10(char *out, const char *hex)
{
int i = 0;
int num;
int carry = 0;
char *ptr;
int N = 0;

/* this does the division */
while(hex)
{
num = carry * 16 + hexval(hex[i++]);
out[N++] = bintohex(num/10);
carry = num % 10;
}
out[N] = 0;

/* remove all leading zeros */
ptr = out;
while(*ptr == '0')
ptr++;
memmove(out, ptr, N + ptr - out);
/* if the number is zero, represent it as a single zero */
if(*out == 0)
strcpy(out, "0");

return carry;
}

/*
function to convert an arbitrary hex string to decimal
Params: dec - return pointer for the decimal number
hex - input pointer to the hex number (no leading 0x)

*/
void hextodecimal(char *dec, const char *hex)
{
char *buff1;
char *buff2;
char temp;
int dig;
int N = 0;
int i;

/* use of the buffers allows us to handle any length of hex */
buff1 = mystrdup(hex);
buff2 = mystrdup(hex);

/* this is a simple algorithm. Divide by ten repeatedly until
the hex number is reduced to zero */
do
{
dig = divideby10(buff2, buff1);
dec[N++] = dig + '0';
strcpy(buff1, buff2);
}
while(strcmp(buff1, "0"));

/* add the trailing NUL */
dec[N] = 0;

/* the decimal number is reversed, so put it right */
for(i=0;i<N/2;i++)
{
temp = dec;
dec = dec[N-i-1];
dec[N-i-1] = temp;
}

/* don't forget to free our resources */
free(buff1);
free(buff2);

}

Hope this is of use to you.
 
B

Bill Hanna

Nathan Waddington said:
Thank you, it very much is.

Use "%I64d" or "%I64u" or "%I64x" in the printf statement to
display 64Bit results. This works on Bloodshed C++ and on MS Visual
C++ . I tested it out.
I found the info from an old posting in 2001.

Bill Hanna
 
G

Giuseppe

int divideby10(char *out, const char *hex)
{
int i = 0;
int num;
int carry = 0;
char *ptr;
int N = 0;

/* this does the division */
while(hex)
{
num = carry * 16 + hexval(hex[i++]);
out[N++] = bintohex(num/10);
carry = num % 10;
}
out[N] = 0;

/* remove all leading zeros */
ptr = out;
while(*ptr == '0')
ptr++;
> memmove(out, ptr, N + ptr - out);


Why not memmove(out, ptr, N - (ptr - out) + 1 ); ?
 
G

Gerald S.

Malcolm said:
Nathan Waddington said:
My program receives a string representation of a 64bit hex number that
needs to be displayed as the decimal number it represents. The compiler
that is being used is Dynamic C and (alas) it does not support 64bit
numbers.
I found this surprisingly hard, when you can't hold the number in
intermediate binary.

Here's what I came up with (tested, but not exhaustively).

/*
convenience function to duplicate a string
*/
char *mystrdup(const char *str)
{
char *answer;

answer = malloc(strlen(str) + 1);

/* you will have to decide your out of memory strategy */
if(!answer)
exit(EXIT_FAILURE);

strcpy(answer, str);
return answer;
}

/*
convert a hex digit to binary
*/
int hexval(char hex)
{
static char *digits = "0123456789ABCDEF";
char *pos;

hex = toupper(hex);
pos = strchr(digits, hex);
assert(pos);

return pos - digits;
}

/*
convert a binary number 0-16 to a hex digit
*/
char bintohex(int val)
{
static char *digits = "0123456789ABCDEF";

assert(val >= 0 && val < 16);
return digits[val];
}

/*
divide a hex number by ten, in hexadecimal
out - return pointer for answer (in hex);
hex - input number
returns - the remainder
*/
int divideby10(char *out, const char *hex)
{
int i = 0;
int num;
int carry = 0;
char *ptr;
int N = 0;

/* this does the division */
while(hex)
{
num = carry * 16 + hexval(hex[i++]);
out[N++] = bintohex(num/10);
carry = num % 10;
}
out[N] = 0;

/* remove all leading zeros */
ptr = out;
while(*ptr == '0')
ptr++;
memmove(out, ptr, N + ptr - out);
/* if the number is zero, represent it as a single zero */
if(*out == 0)
strcpy(out, "0");

return carry;
}

/*
function to convert an arbitrary hex string to decimal
Params: dec - return pointer for the decimal number
hex - input pointer to the hex number (no leading 0x)

*/
void hextodecimal(char *dec, const char *hex)
{
char *buff1;
char *buff2;
char temp;
int dig;
int N = 0;
int i;

/* use of the buffers allows us to handle any length of hex */
buff1 = mystrdup(hex);
buff2 = mystrdup(hex);

/* this is a simple algorithm. Divide by ten repeatedly until
the hex number is reduced to zero */
do
{
dig = divideby10(buff2, buff1);
dec[N++] = dig + '0';
strcpy(buff1, buff2);
}
while(strcmp(buff1, "0"));

/* add the trailing NUL */
dec[N] = 0;

/* the decimal number is reversed, so put it right */
for(i=0;i<N/2;i++)
{
temp = dec;
dec = dec[N-i-1];
dec[N-i-1] = temp;
}

/* don't forget to free our resources */
free(buff1);
free(buff2);

}

Hope this is of use to you.


Hi Malcom,

this is exactly what I was searching for. I needed a string based
conversion routine for a language called SMALL. As this (C derived)
language only supports 32Bit integers your routine is just what i
need.

Thx, Gerald
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,262
Messages
2,571,045
Members
48,769
Latest member
Clifft

Latest Threads

Top