将长十六进制字符串转换为十进制字符串

时间:2012-05-15 16:48:28

标签: c string numbers

我需要找出一种在标准C中执行以下操作的方法。假设我们给出一个表示十六进制数字的字符串,其中包含n个数字。我们想将其转换为表示十进制相同数字的字符串。字符串可以具有任意数量的数字。至少容易推断的是十进制字符串需要< = 2n个字母。

一旦我们达到机器可以处理的数字的大小限制,那么字符串的长度变得非常无关紧要,因此具有100位数字的十六进制数字应该与具有1000位数字的数字一样容易/难以转换,即同样的算法应该适用于两者,因为它必须以块的形式工作。

有没有人在这想过这个?真正令人讨厌的是2的大功率在第一个数字下都有非零数字,所以十六进制序列中的任何元素都会影响十进制的最后一个数字......

我只能找到有人希望字符串转换为数字或数字到某个字符串中的字符串的问题。如果有人想知道我为什么需要这个。我正在玩任意精确数字,最经济的存储数字格式是256,所以我需要打印这种形式的数字(或者等效的任何十六进制数字)。

编辑:所以我实现了转换功能,如果其他人可能需要它我会在这里分享。这非常快,一个更好的实现当然可以通过用动态分配的东西替换struct中的数字缓冲区来开始。由于所有算术都发生在“add”函数中,因此如果加法溢出,则可以很容易地将此​​缓冲区重新分配给更大的值。输出缓冲区大小总是很容易分配,因为任何十六进制数转换为十进制数,小于或等于两位数。

#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;
            }
        }
    }
}

0 个答案:

没有答案