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

Posted

技术标签:

【中文标题】将长十六进制字符串转换为十进制字符串【英文标题】:Converting a long hexadecimal string to a decimal string 【发布时间】:2012-05-15 16:48:28 【问题描述】:

我需要想办法在标准 C 中执行以下操作。假设我们得到一个字符串,表示一个十六进制数字,比如 n 位数字。我们希望将其转换为以十进制表示相同数字的字符串。字符串可以有任意位数。至少很容易推断的是,十进制字符串需要

一旦我们达到机器可以处理的数字的大小限制,那么字符串的长度就变得无关紧要了,所以一个 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;
            
        
    

【问题讨论】:

听起来你需要在谷歌周围搜索“c 大整数实现” 我同意@Colin。这里的问题是您必须将数字 n(其中单位为数字 0)乘以 16^n 才能获得十进制等值。由于您的 n 可能很大(100 或 1,000,来自您的帖子),您必须能够对非常大的数字进行求幂,这将需要一个大整数实现。 好吧,没有我想象的那么糟糕。由于您只需要以小于 16 的底数取幂,因此我们仍然可以执行简单的求幂算法,而无需实现除以 2。 【参考方案1】:

请注意此代码中存在错误。只要十六进制字符串包含 0 ! 这个sn-p:

/* 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。所以我建议在第一个函数中将 sn-p 替换为:

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

【讨论】:

以上是关于将长十六进制字符串转换为十进制字符串的主要内容,如果未能解决你的问题,请参考以下文章

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

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

将长整数转换为字符/符文

[PTA]实验8-2-9 长整数转化成16进制字符串

类型转换

将十进制字符串转换为十六进制字符串而不将字符串转换为整数