我有一个uint8_t *
数组,其中包含任意精确数bigendian编码。
我想得到它的十进制Ascii表示。所以我需要编写一个返回char *
。
由于硬件限制,我正在使用的环境不允许我导入任何任意精度库。
我确信有一些东西我可以阅读以轻松实现它。
例如,以下十六进制d53ceb9d32c6ca06
定义的数字应由15365415089075571206
表示。
答案 0 :(得分:-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 = "0123456789abcdefghijklmnopqrstuvwxyz";
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;
}