2017-10-15 89 views
0

我有一个uint8_t *数组,其中包含任意精确数字bigendian编码。任意精度数字ascii在c

我想要得到它的十进制Ascii表示。所以我需要编写一个返回char *的函数。

由于硬件限制,我使用的环境不允许导入任何任意精度库。

我确定有一些东西我可以阅读,以轻松实现它。

例如,由以下十六进制定义的数字十六进制d53ceb9d32c6ca06应该由15365415089075571206表示。

+0

你能举个例子吗?甚至可能是[mcve]? – Yunnosch

+2

基本上,你必须实施长期分工。 –

+0

这取决于您需要在文本和数字之间进行多少转换。如果使用基数'100'而不是'256',则文本输出几乎是微不足道的,但是有一个折衷,因为您的bignum的算术计算需要使用效率较低的'%'而不是'&'来分隔部分总和,产品等 –

回答

-1

下面是一个应该工作的方法。请注意,它会破坏性地修改您传递给它的bigint,因此如果您关心那里的值,请在调用方法之前将其复制到临时临时缓冲区。此外,这不是您可以编写的最优化版本,但如果您在此处询问如何执行此操作,那么您可能并不关心与此有关的微型优化。

#include <stdint.h> 
#include <stdbool.h> 
#include <stdio.h> 
#include <stdlib.h> 

bool is_zero(uint8_t *bigi_data, int bigi_size) { 
    int i = 0; 

    while((i < bigi_size) && (bigi_data[i] == 0)) { 
     i++; 
    } 
    return (i >= bigi_size); 
} 

uint8_t bigdivmod(uint8_t *bigi_data, int bigi_size, uint8_t divisor) { 
    int i = 0; 
    uint16_t ans = 0; 

    while((i < bigi_size) && (bigi_data[i] == 0)) { 
     i++; 
    } 
    for (; i < bigi_size; i++) { 
     ans = ans*256 + bigi_data[i]; 
     bigi_data[i] = ans/divisor; 
     ans = ans % divisor; 
    } 
    return (uint8_t)ans; 
} 

static const char *digits = "abcdefghijklmnopqrstuvwxyz"; 

char *bigitoa(uint8_t *bigi_data, int bigi_size, char *out, int base) { 
    /* Assumes that "out" has enough room. DESTRUCTIVE TO BIGI, so copy */ 
    /* if you care about the value */ 
    /* Only really works for non-negative values */ 
    int i = 0; 
    uint8_t swp; 
    int j; 

    if ((base < 2) || (base > 36)) { 
     return NULL; 
    } 

    if (is_zero(bigi_data, bigi_size)) { 
     out[0] = '0'; 
     out[1] = '\0'; 
     return out; 
    } 

    while (!is_zero(bigi_data, bigi_size)) { 
     out[i++] = digits[bigdivmod(bigi_data, bigi_size, base)]; 
    } 
    out[i] = 0; 
    for (j = 0; j < i/2; j++) { 
     swp = out[i - 1 - j]; 
     out[i - 1 - j] = out[j]; 
     out[j] = swp; 
    } 

    return out; 
} 

int main(int argc, char *argv[]) { 
    uint8_t test_data[] = { 0xd5, 0x3c, 0xeb, 0x9d, 0x32, 0xc6, 0xca, 0x06 }; 
    int test_data_len = sizeof(test_data); 
    char *p; 

    /* Times 3 because we can use three digits to represent 256. If changing */ 
    /* the base below from "10", change this factor. */ 
    p = malloc(3*test_data_len + 1); 

    printf("Test data works out to %s\n", 
      bigitoa(test_data, test_data_len, p, 10)); 

    return 0; 
}