Getting a 128 bits integer from command line - c

I'm trying to cast an unsigned long long key to do the Tiny Encryption Algorithm algorithm.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv){
unsigned int key[4] = { 0 };
*key = strtoll(argv[1], NULL, 10);
printf("%s key = %llu\n", argv[0], key);
return 0;
}
Here is my input :
./a.out 9223372036854775700
Here is the output :
./a.out key = 140723741574976
So I'm passing a 128 bit key in argv[1]. Shouldn't it be cast properly in memory into the unsigned int array?
So, I'm trying to figure out why this is the output of my program. Does this have something to do with endianness?

long long is only specified to contain at least 64 bits. You might be better off passing your key as hex and parsing it manually into a byte array

Take a step back, and look at what you are trying to implement. The Tiny Encryption Algorithm does not work on an 128-bit integer, but on a 128-bit key; the key is composed of four 32-bit unsigned integers.
What you actually need, is a way to parse a decimal (or hexadecimal, or some other base) 128-bit unsigned integer from a string to four 32-bit unsigned integer elements.
I suggest writing a multiply-add function, which takes the quad-32-bit value, multiplies it by a 32-bit constant, and adds another 32-bit constant:
#include <stdint.h>
uint32_t muladd128(uint32_t quad[4], const uint32_t mul, const uint32_t add)
{
uint64_t temp = 0;
temp = (uint64_t)quad[3] * (uint64_t)mul + add;
quad[3] = temp;
temp = (uint64_t)quad[2] * (uint64_t)mul + (temp >> 32);
quad[2] = temp;
temp = (uint64_t)quad[1] * (uint64_t)mul + (temp >> 32);
quad[1] = temp;
temp = (uint64_t)quad[0] * (uint64_t)mul + (temp >> 32);
quad[0] = temp;
return temp >> 32;
}
The above uses most significant first word order. It returns nonzero if the result overflows; in fact, it returns the 32-bit overflow itself.
With that, it is very easy to parse a string describing a nonnegative 128-bit integer in binary, octal, decimal, or hexadecimal:
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
static void clear128(uint32_t quad[4])
{
quad[0] = quad[1] = quad[2] = quad[3] = 0;
}
/* muladd128() */
static const char *parse128(uint32_t quad[4], const char *from)
{
if (!from) {
errno = EINVAL;
return NULL;
}
while (*from == '\t' || *from == '\n' || *from == '\v' ||
*from == '\f' || *from == '\r' || *from == ' ')
from++;
if (from[0] == '0' && (from[1] == 'x' || from[1] == 'X') &&
((from[2] >= '0' && from[2] <= '9') ||
(from[2] >= 'A' && from[2] <= 'F') ||
(from[2] >= 'a' && from[2] <= 'f'))) {
/* Hexadecimal */
from += 2;
clear128(quad);
while (1)
if (*from >= '0' && *from <= '9') {
if (muladd128(quad, 16, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
if (*from >= 'A' && *from <= 'F') {
if (muladd128(quad, 16, *from - 'A' + 10)) {
errno = ERANGE;
return NULL;
}
from++;
} else
if (*from >= 'a' && *from <= 'f') {
if (muladd128(quad, 16, *from - 'a' + 10)) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
if (from[0] == '0' && (from[1] == 'b' || from[1] == 'B') &&
(from[2] >= '0' && from[2] <= '1')) {
/* Binary */
from += 2;
clear128(quad);
while (1)
if (*from >= '0' && *from <= '1') {
if (muladd128(quad, 2, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
if (from[0] == '0' &&
(from[1] >= '0' && from[1] <= '7')) {
/* Octal */
from += 1;
clear128(quad);
while (1)
if (*from >= '0' && *from <= '7') {
if (muladd128(quad, 8, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
if (from[0] >= '0' && from[0] <= '9') {
/* Decimal */
clear128(quad);
while (1)
if (*from >= '0' && *from <= '9') {
if (muladd128(quad, 10, *from - '0')) {
errno = ERANGE;
return NULL;
}
from++;
} else
return from;
}
/* Not a recognized number. */
errno = EINVAL;
return NULL;
}
int main(int argc, char *argv[])
{
uint32_t key[4];
int arg;
for (arg = 1; arg < argc; arg++) {
const char *end = parse128(key, argv[arg]);
if (end) {
if (*end != '\0')
printf("%s: 0x%08x%08x%08x%08x (+ \"%s\")\n", argv[arg], key[0], key[1], key[2], key[3], end);
else
printf("%s: 0x%08x%08x%08x%08x\n", argv[arg], key[0], key[1], key[2], key[3]);
fflush(stdout);
} else {
switch (errno) {
case ERANGE:
fprintf(stderr, "%s: Too large.\n", argv[arg]);
break;
case EINVAL:
fprintf(stderr, "%s: Not a nonnegative integer in binary, octal, decimal, or hexadecimal notation.\n", argv[arg]);
break;
default:
fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
break;
}
}
}
return EXIT_SUCCESS;
}
It is very straightforward to add support for Base64 and Base85, which are sometimes used; or indeed for any base less than 232.
And, if you think about the above, it was all down to being precise about what you need.

Code is attempting to print the address of the array key[0] rather than its value. This is not an endian-ness issue. Enable all compiler warnings to save time.
*key = strtoll(argv[1], NULL, 10); attempts to save a long long (at least 64-bit) into a unsigned int, which is likely only 32.
The string "9223372036854775700" represents a 63 bit number.
First try to use an unsigned long long which is at least a 64-bit number.
int main(int argc, char** argv){
// unsigned int key[4] = { 0 };
unsigned long long key = strtoull(argv[1], NULL, 10);
printf("%s key = %llu\n", argv[0], key);
return 0;
}
C does not specify support for 128-bit integers. User code could be written to cope with that. #C_Elegans idea of using hexadecimal text is good.
As int could be of various sizes, better to use
#include <stdint.h>
// unsigned int key[4];
uint32_t key[4];
A sample code idea
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
uint16_t u[8];
} my_uint128_t;
my_uint128_t strtomy_uint128(const char *s, char **endptr, int base) {
my_uint128_t y = {0};
while (isalnum((unsigned char ) *s)) {
char *endptr;
uint32_t sum = (uint32_t) strtoul((char[2]) {*s, '\0'}, &endptr, base);
if (*endptr) {
break;
}
for (int i = 0; i < 8; i++) {
sum += y.u[i] * (uint32_t) base;
y.u[i] = (uint16_t) sum;
sum >>= 16;
}
if (sum) {
errno = ERANGE;
for (int i = 0; i < 8; i++) {
y.u[i] = UINT16_MAX;
}
}
s++;
}
if (endptr) {
*endptr = (char *) s;
}
return y;
}
void uint128_dump(my_uint128_t x) {
for (int i = 8; i > 0; ) {
i--;
printf("%04" PRIX16 "%c", x.u[i], i ? ' ' : '\n');
}
}
int main(void) {
my_uint128_t a = strtomy_uint128("9223372036854775700", 0, 10);
uint128_dump(a);
}
Output
0000 0000 0000 0000 7FFF FFFF FFFF FF94

Why not do it manually? Get a __int128 type variable, go through each digit of your input and insert it in your variable as such:
int main(int argc, char** argv){
__int128 key = 0;
int i;
for (i=0; i<strlen(argv[1]); i++){
key *= 10; // "shift" current value to make space for adding one more decimal
key += argv[1][i] - '0'; // convert ascii character to number
}
printf("%s key = %llu\n", argv[0], key);
return 0;
}
Note that if argv[1] is too long the key will discard its first digits rather than its last. So, maybe that's something you need to take care of too, according to your preferences

Related

A c program to convert from octal to decimal

I'm trying to figure what is wrong with my code as it always skips only to the printf("not an octal number part"); and only outputs that although has many of the other computations before it, i'm trying to debug it but can't seem to find the error. this is the summer of the problem below, also we are not allowed to use pointers yet.
A C program to input an octal number in the form of a line of characters and store the input characters in an array. Convert the octal number to a decimal integer and display the decimal integer on the standard output using printf.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 100
int main() {
char my_strg[MAX_SIZE];
int c;
int res = 0;
int i = 0;
while ( (c = getchar()) != '\n') {
my_strg[i] = c;
i++;
}
int k = 0;
for(k = strlen(my_strg)-1; k >= 0; k--) {
if((my_strg[k] >= '0') && (my_strg[k] <= '7')) {
res += (pow(8, k) * (my_strg[k]-'0'));
} else if(my_strg[k] == '-') {
res *= -1;
} else {
printf("not an octal number");
break;
}
k++;
}
printf("%d\n", res);
}
You haven't null-terminated my_strg. This means that the beginning of the array contains the input, but the rest of it contains gibberish. It may also be a good idea to do bounds checking so that you don't get a buffer overflow.
while (((c = getchar()) != '\n') && (i < MAX_SIZE-1)) {
my_strg[i] = c;
my_strg[i+1] = '\0';
i++;
}
very simple function. Needs more error checking.
Note 'a' != 'A'. The base can be as big as number of chars in the digits table
static const char digits[] = "0123456789abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRTSTUWXYZ";
long long ALMOST_anybase(const char *str, int base, int *errCode)
{
long long result = 0;
int sign = 1;
if(errCode) *errCode = 0;
if(str)
{
if(*str == '-') {sign = -1; str++;}
while(*str)
{
if(*str == '-')
{
if(errCode) *errCode = 3;
break;
}
else
{
char *ch;
if((ch = strchr(digits, *str)))
{
if(ch - digits >= base)
{
if(errCode) *errCode = 2;
break;
}
result *= base;
result += (ch - digits);
}
else
{
if(errCode) *errCode = 1;
break;
}
}
str++;
}
}
return result * sign;
}
int main(void)
{
int errCode;
long long result;
result = ALMOST_anybase("-4-4", 10, &errCode);
if(errCode)
{
printf("Wrong input string ErrCode = %d\n", errCode);
}
else
{
printf("result = %lld\n", result);
}
}

Converting a multidigital integer from a char array into an integer

I've build a small program which would convert the given char array to an integer:
#include <stdio.h>
int char_to_int(char* value);
int main(int argc, char* argv[])
{
if (argc != 2)
{
printf("Illegal argument count!");
return 1;
}
printf("As char array: %s\n", argv[1]);
printf("As integer: %i", char_to_int(argv[1]));
return 0;
}
int char_to_int(char* value)
{
return *value - '0';
}
The problem is that when I enter a multidigital number the integer only consists of a single digit number, which is logical, but I have no idea on how to rewrite the code. And I also have no idea why only the first char gets converted.
I know this is pretty basic stuff, but I'd like to know how to implement it correctly.
I'd also like to avoid using the ato() function in the STL.
Reworked code with error handling:
#include <stdio.h>
int char_to_int(char* value);
int illegal_conversion = 0;
int main(int argc, char* argv[])
{
if (argc != 2)
{
printf("Illegal argument count!");
return 1;
}
int result = char_to_int(argv[1]);
if (illegal_conversion)
{
printf("Illegal arguments");
return 1;
}
printf("As char array: %s\n", argv[1]);
printf("As integer: %i", result);
return 0;
}
int char_to_int(char* value)
{
int result = 0;
int negative_integer = 0;
while (*value)
{
if (*value == 43)
{
*value++;
continue;
}
else if (*value == 45)
{
*value++;
negative_integer = 1;
continue;
}
else if (*value < 48 || *value > 57)
{
illegal_conversion = 1;
return 1;
}
result *= 10;
result += *value++ - '0';
}
if (negative_integer)
result *= -1;
return result;
}
Because you only return the numerical value of the first digit.
This function converts but without any checks and it works only for the valid non negative decimal numbers, otherwise it is an UB
int char_to_int(char* value)
{
int result = 0;
while(*value)
{
result *= 10;
result += *value++ - '0';
}
return result;
}
or a bit smarter one:
int char_to_int(char* value, int *res)
{
int sign = 0;
int status = 0;
int result = 0;
if (value != NULL && res != NULL)
{
while (*value)
{
switch (*value)
{
case '+':
case '-':
if (sign) status = -1;
sign = *value == '-' ? -1 : 1;
break;
default:
if (!isdigit(*value)) status = -1;
if(!sign) sign = 1;
*result *= 10;
*result += *value - '0';
break;
}
value++;
if (status) break;
}
if(!status)*res = sign * result;
}
return status;
}
Reworked code incurs undefined behavior in a case where it can be avoided.
Example with (2's complement) int
char buf[100];
sprintf(buf, "%d", INT_MIN); // e.g. -2147483648
int y = char_to_int(buf);
The while loop in char_to_int() eventually executes
// before
// result: 214748364
// *value: '8'
result += *value++ - '0';
// after
// `int` overflow, this is undefined behavior
To avoid, rather than accumulate the answer as a positive value and then later negate if '-' found, accumulate the answer as a negative value and then later negate if '-' not found. This is less intuitive, yet avoids UB.
Using unsigned as an extended range is another way, yet that fails on rare machines where INT_MAX == UINT_MAX. I have only encountered such a machine once and that for for its widest integer.
Other improvements noted in comments.
#include <ctype.h>
int char_to_int(const char *value) { // use const
int sign = *value;
if (sign == '-' || sign == '+') {
value++;
}
bool digit_found = false;
int result = 0;
// while (isdigit(*value)) { // avoid this as it is UB when *value < 0, not EOF
while (isdigit((unsigned char) *value)) { // or (*value >= '0' && *value <= '9')
result *= 10;
result -= *value - '0'; // notice the `-=`
value++;
digit_found = true;
}
if (sign != '-') {
result = -result;
}
// Error detection
if (*value != '\0' || !digit_found) {
; //Handle_Invalid_String();
}
return result;
}
Note: overflow detection not included.

Parsing a hexadecimal string representation as an integer

How can I parse a string like "0000000f" as an unsigned long long int? And for larger values, how can I parse a string like "0000000f,0000000f" representing respectively the upper and lower 32 bits?
P.S. Can't use library functions in this issue.
You can use strtoull() from <stdlib.h> this way:
#include <stdlib.h>
unsigned long long parse_u64(const char *s) {
unsigned long long v1;
v1 = strtoull(s, (char **)&s, 16);
if (*s == ',') {
v1 = (v1 << 32) | strtoull(s + 1, NULL, 16);
}
return v1;
}
Note that formatting errors are not detected.
If you cannot rely on library functions, use this:
int getdigit(int c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return -1;
}
unsigned long long parse_u64(const char *s) {
unsigned long long v1;
int digit;
for (v1 = 0; *s; s++) {
if (*s == ',')
continue;
digit = getdigit(*s);
if (digit < 0)
break;
v1 = (v1 << 4) | digit;
}
return v1;
}
You can choose to ignore spaces and other characters or to stop parsing as I did.
Like #chqrlie, but with additional error checking,
Sounds like you want a string to integer conversion. Simply enough:
unsigned chtohex(char ch) {
if (ch >= '0' && ch <= '9') return ch - '0';
if (ch >= 'A' && ch <= 'Z') return ch - 'A' + 10;
if (ch >= 'a' && ch <= 'a') return ch - 'a' + 10;
return (unsigned) -1;
}
// return 0 on success,1 on failure
int my_hexstrtoull(const char *s, unsigned long long *dest) {
unsigned long long sum = 0;
unsigned ch;
while (*s) {
if (*s == ',') continue;
unsigned ch = chtohex(*s++);
if (ch >= 16) {
return 1; // Bad hex char
}
if (sum >= ULLONG_MAX/16) {
return 1; // overflow
}
sum = sum * 16 + ch;
s++;
}
*dest = sum;
return 0;
}
Here's a simple solution using scanf:
#include <stdio.h>
#include <stdlib.h>
unsigned long long int parse(char const * s)
{
unsigned long int a, b;
if (sscanf(s, "%8lx,%8lx", &a, &b) == 2)
return ((unsigned long long int) a << 32) + b;
if (sscanf(s, "%8lx", &a) == 1)
return a;
abort();
}

Using unsigned int instead of unsigned short changes behaviour

I am attempting the htoi(char*) function from The C Programming Language by K&R (Excercise 2-3, pg. 43).
The function is meant to convert a hexadecimal string to base 10.
I believe I have it working. This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
enum {hexbase = 16};
typedef enum{false, true} bool;
unsigned int htoi(char* s);
bool hasHexPrefix(char* s);
int main(int argc, char** argv) {
if(argc <= 1) {
printf("Error: Not enough arguments.\n");
return EXIT_FAILURE;
}else {
for(int i = 1; i < argc; i++) {
unsigned int numericVal = htoi(argv[i]);
printf("%s => %u\n",argv[i],numericVal);
}
}
}
unsigned int htoi(char* s) {
unsigned int output = 0;
unsigned int len = (unsigned int)(strlen(s));
unsigned short int firstIndex = hasHexPrefix(s) ? 2 : 0;
/* start from the end of the str (least significant digit) and move to front */
for(int i = len-1; i >= firstIndex; i--) {
int currentChar = s[i];
unsigned int correspondingNumericVal = 0;
if(currentChar >= '0' && currentChar <= '9') {
correspondingNumericVal = currentChar - '0';
}else if(currentChar >= 'a' && currentChar <= 'f') {
correspondingNumericVal = (currentChar - 'a') + 10;
}else if(currentChar >= 'A' && currentChar <= 'F') {
correspondingNumericVal = (currentChar - 'A') + 10;
}else {
printf("Error. Invalid hex digit: %c.\n",currentChar);
}
/* 16^(digitNumber) */
correspondingNumericVal *= pow(hexbase,(len-1)-i);
output += correspondingNumericVal;
}
return output;
}
bool hasHexPrefix(char* s) {
if(s[0] == '0')
if(s[1] == 'x' || s[1] == 'X')
return true;
return false;
}
My issue is with the following line from the htoi(char*) function:
unsigned short int firstIndex = hasHexPrefix(s) ? 2 : 0;
When I remove short to make firstIndex into an unsigned int rather than an unsigned short int, I get an infinite loop.
So when I start from the back of s in htoi(char* s), i >= firstIndex never evaluates to be false.
Why does this happen? Am I missing something trivial or have I done something terribly wrong to cause this undefined behavior?
When firstIndex is unsigned int, in i >= firstIndex then i is converted to unsigned int because of the usual arithmetic conversions. So if i is negative it becomes a large integer in the comparison expression. When firstIndex is unsigned short int in i >= firstIndex, firstIndex is promoted to int and two signed integers are compared.
You can change:
for(int i = len-1; i >= firstIndex; i--)
to
for(int i = len-1; i >= (int) firstIndex; i--)
to have the same behavior in both cases.

Converting a long hexadecimal string to a decimal string

I would need to figure out a way to do the following in standard C. Assume we are given a string representing a hexadecimal number with say n digits. We want to convert this to a string representing the same number in decimal. The strings could have an arbitrary number of digits. What's at least easy to deduce is that the decimal string needs <= 2n letters.
Once we reach the size limit for numbers that the machine can handle, then the length of the string becomes quite irrelevant, so a hexadecimal number with 100 digits should be just as easy/hard to convert as one with 1000 digits i.e. the same algorithm should work on both as it has to work in chunks.
Has anyone here thought about this? What's really annoying is that large powers of 2 have nonzero digits down to the first order, so any element in the hexadecimal sequence can affect the last digit in decimal...
I could only find questions where someone wanted a string converted to a number or a number to a string in some base. If someone wonders why I would need this. I'm playing around with arbitrary precision numbers and the most economical format for storing numbers in is base 256, so I need to print numbers given in this form (or equivalently any hexadecimal).
EDIT: So I implemented a conversion function and I'll share it here if anyone else might ever need it. This was very quick an dirty and a better implementation would of course start by replacing the digits buffer in the struct by something that gets dynamically allocated. Since all arithmetic happens in the "add" function it would then be easy to realloc this buffer to something bigger if an addition overflows. The output buffer size is always simple to assign, since any hexadecimal number converts to a decimal number with less or equal to twice the digits.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 1000
struct number {
unsigned char digits[MAXLEN];
unsigned int num_digits;
};
int add(struct number *, struct number *, struct number *);
int mult(struct number *, struct number *, struct number *);
int power(struct number *, unsigned int, struct number *);
void print_number(struct number *, char *);
void dec(struct number *);
void hex2dec(char *hex, char *outbuf)
{
int n;
char *s;
struct number decrep;
struct number twopow;
struct number digit;
decrep.num_digits = 0;
n = strlen(hex);
s = hex;
while(--n > -1) {
/* weight of digit */
twopow.num_digits = 2;
twopow.digits[0] = 6;
twopow.digits[1] = 1;
power(&twopow, n, &twopow);
/* Extract digit */
if(*s <= '9' && *s >= '0') {
digit.digits[0] = *s - '0';
digit.num_digits = 1;
} else if(*s <= 'f' && *s >= 'a') {
digit.digits[0] = *s - 'a';
digit.digits[1] = 1;
digit.num_digits = 2;
} else if(*s <= 'F' && *s >= 'A') {
digit.digits[0] = *s - 'A';
digit.digits[1] = 1;
digit.num_digits = 2;
}
s++;
mult(&digit, &twopow, &digit);
add(&decrep, &digit, &decrep);
}
/* Convert decimal number to a string */
if(decrep.num_digits == 0) {
*outbuf = '0';
*(++outbuf) = '\0';
return;
}
for(n = decrep.num_digits-1; n >= 0; n--) {
*(outbuf++) = '0' + decrep.digits[n];
}
*outbuf = '\0';
}
int main(void)
{
char buf[1000];
hex2dec("FFEa4334234FABCD", buf);
printf("%s", buf);
return 0;
}
void copy_number(struct number *dst, struct number *src)
{
int i;
for(i = 0; i < src->num_digits; i++) dst->digits[i] = src->digits[i];
dst->num_digits = src->num_digits;
}
int power(struct number *a, unsigned int n, struct number *b)
{
struct number atmp;
/* Are we exponentiating by 0? */
if(n == 0) {
b->num_digits = 1;
b->digits[0] = 1;
return 0;
}
copy_number(&atmp, a);
while(--n > 0) {
mult(&atmp, a, &atmp);
}
copy_number(b, &atmp);
return 0;
}
int mult(struct number *a, struct number *b, struct number *c)
{
struct number btmp;
struct number ctmp;
struct number *t;
/* Are we multiplying by 0? */
if(a->num_digits == 0 || b->num_digits == 0) {
c->num_digits = 0;
return 0;
}
if(a->num_digits < b->num_digits) {
t = a;
a = b;
b = t;
}
copy_number(&btmp, b);
copy_number(&ctmp, a);
while(1) {
/* Are we multiplying by 1? */
if(btmp.num_digits == 1 && btmp.digits[0] == 1) {
break;
}
add(&ctmp, a, &ctmp);
dec(&btmp);
}
copy_number(c, &ctmp);
return 0;
}
int add(struct number *a, struct number *b, struct number *c)
{
int i, j;
int carry;
struct number *t;
if(a->num_digits < b->num_digits) {
t = a;
a = b;
b = t;
}
for(i = 0, carry = 0; i < a->num_digits; i++) {
if(i >= b->num_digits) j = a->digits[i]+carry;
else j = a->digits[i]+b->digits[i]+carry;
if(j > 9) {
j -= 10;
carry = 1;
} else {
carry = 0;
}
c->digits[i]=j;
}
/* Did we overflow? */
if(carry > 0 && i == MAXLEN) return -1;
/* Carry over from last addition? */
if(carry > 0) {
c->digits[i] = carry;
c->num_digits = a->num_digits+1;
} else {
c->num_digits = a->num_digits;
}
return 0;
}
void print_number(struct number *a, char *buf)
{
int i;
if(a->num_digits == 0) {
printf("0");
return;
}
for(i = a->num_digits-1; i >= 0; i--) {
*(buf++) = '0' + a->digits[i];
}
*buf = '\0';
}
void dec(struct number *a)
{
int i;
for(i = 0; i < a->num_digits; i++) {
if(a->digits[i] > 0) {
a->digits[i]--;
break;
}
a->digits[i] = 9;
}
/* Did number of digits get lower */
if(i == a->num_digits -1 && a->digits[i] == 0) {
for(i = a->num_digits - 1; i >= 0; i--) {
if(a->digits[i] != 0) {
a->num_digits = i + 1;
break;
}
}
}
}
Please note there is a bug in this code. As soon as the HEX string contains a 0 !
this snippet :
/* Extract digit */
if(*s <= '9' && *s >= '0') {
digit.digits[0] = *s - '0';
digit.num_digits = 1;
} else if(*s <= 'f' && *s >= 'a') {
gives digits[0] = 0; num_digites = 1;
But later in the mult() function there is the snipet :
if(a->num_digits == 0 || b->num_digits == 0) {
c->num_digits = 0;
return 0;
}
that test 0 by num_digits == 0. So I suggest to replace in the first function the snippet with :
if(*s == '0') {
digit.digits[0] = *s - '0';
digit.num_digits = 0;
}else if(*s <= '9' && *s > '0') {
digit.digits[0] = *s - '0';
digit.num_digits = 1;
} else if(*s <= 'f' && *s >= 'a') {
looks to work fine for me.
You can compare the result on this site : http://www.statman.info/conversions/hexadecimal.php

Resources