2017-10-15 4 views
0

Ich habe ein uint8_t * Array, das eine beliebige Genauigkeitsnummer enthält, die von Bigendian codiert wird.Beliebige Genauigkeitszahl zu Ascii in c

Ich möchte seine Dezimal Ascii Darstellung erhalten. Also müsste ich eine Funktion schreiben, die eine char * zurückgibt.

Die Umgebung, die ich benutze, erlaubt mir aufgrund von Hardwarebeschränkungen keine beliebige Präzisions-Bibliothek zu importieren.

Ich bin sicher, es gibt etwas, das ich lesen kann, um es einfach zu implementieren.

Zum Beispiel sollte die durch das folgende Hex d53ceb9d32c6ca06 definierte Zahl durch 15365415089075571206 dargestellt werden.

+0

Können Sie Beispiele geben? Vielleicht sogar ein [MCVE]? – Yunnosch

+2

Im Wesentlichen müssen Sie eine lange Division implementieren. –

+0

Es hängt davon ab, wie viel Konvertierung Sie zwischen Text und Nummer benötigen. Wenn Sie radix '100' statt' 256' verwenden, ist die Textausgabe fast trivial, aber es gibt einen Kompromiss, weil arithmetische Berechnungen mit Ihrem bignum die weniger effizienten '%' anstelle von '&' verwenden müssen, um partiell zu trennen Summen, Produkte usw. –

Antwort

-1

Hier ist eine Methode, die funktionieren sollte. Beachten Sie, dass der bigint, den Sie übergeben, destruktiv geändert wird. Wenn Sie sich also für den Wert interessieren, kopieren Sie ihn in einen temporären Scratch-Puffer, bevor Sie die Methode aufrufen.

Auch dies ist nicht die am besten optimierte Version, die Sie schreiben könnten, aber wenn Sie fragen, wie Sie es hier tun, sind Sie wahrscheinlich noch nicht über Mikro-Optimierung mit diesem Thema.

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