繁体   English   中英

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

[英]Converting a long hexadecimal string to a decimal string

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

一旦我们达到了机器可以处理的数字的大小限制,那么字符串的长度就变得无关紧要了,因此100位数字的十六进制数字与1000位数字的十六进制数字一样容易/很难转换,即相同的算法应该因为必须分块工作,所以两者都可以工作。

这里有人想过吗? 真正令人烦恼的是2的大数幂具有非零位到第一位的数字,因此十六进制序列中的任何元素都可能影响十进制的最后一位...

我只能在有人希望将字符串转换为数字或将数字转换为某个基数的字符串中找到问题。 如果有人想知道为什么我会需要这个。 我正在使用任意精度的数字,最经济的存储数字格式为256,因此我需要打印以此形式给出的数字(或等效的任何十六进制)。

编辑:所以我实现了转换功能,如果有人可能需要它,我会在这里分享。 这是一个非常肮脏的过程,当然,更好的实现方式是从结构中的数字缓冲区替换为动态分配的东西开始。 由于所有算术都发生在“ 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! 这个片段:

/* Extract digit */
if(*s <= '9' && *s >= '0') {
    digit.digits[0] = *s - '0';
    digit.num_digits = 1;
} else if(*s <= 'f' && *s >= 'a') {

给出数字[0] = 0; num_digites = 1; 但是稍后在mult()函数中有一个片段:

if(a->num_digits == 0 || b->num_digits == 0) {
    c->num_digits = 0;
    return 0;
}

通过num_digits == 0来测试0。因此,我建议在第一个函数中将代码段替换为:

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') {

看起来对我来说很好。 您可以在以下站点上比较结果: http : //www.statman.info/conversions/hexadecimal.php

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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