2016-04-06 42 views
2

Bir Hex dizesini Ascii dizesine dönüştürmem gerekiyor. Sadece printf ile değil, aynı zamanda hafızaya kaydetmek için. Bu kodu görüntülemek için kullanıyorum ama kaydetmek istiyorum. NasılBir Hex char arabellek ASCII dizesine nasıl dönüştürülür [C]

#include <stdio.h> 
#include <string.h> 

int hex_to_int(char c){ 
     int first = c/16 - 3; 
     int second = c % 16; 
     int result = first*10 + second; 
     if(result > 9) result--; 
     return result; 
} 

int hex_to_ascii(char c, char d){ 
     int high = hex_to_int(c) * 16; 
     int low = hex_to_int(d); 
     return high+low; 
} 

int main(){ 
     const char st[12] = "48656C6C6F3B"; 
     int length = strlen(st); 
     int i; 
     char buf = 0; 
     for(i = 0; i < length; i++){ 
       if(i % 2 != 0){ 
         printf("%c", hex_to_ascii(buf, st[i])); 
       }else{ 
         buf = st[i]; 
       } 
     } 
} 

Benim ilk çözüm döngü int sprintf(buf,"%c",hex_to_ascii(buf,st[i]) kullanmaktı ?: yapabilirsiniz ancak sprintfchar bir işaretçi gerektiğinden bu çözüm işe yaramaz.

+2

'sprintf() 'kesinlikle'% C' dönüşüm için bir işaretçi gerek yoktur. Ama ihtiyacınız olan karaktere sahipseniz, sadece saklayın. – unwind

+0

Bir "Hex dizgisini" bir "ASCII dizesine" dönüştürürken, tasarım burada tanımlanmayan şeylere bağlıdır: 1) Altıgen dize her zaman iyi biçimlendirilecek ve sonuç ne değilse ne olacak? 2) A-F ve a-f'yi kullanın? 3) Sonuç dizesi için arabelleği ne ayırır? 4) "00" nasıl ele alınır? 5) ASCII olmayan taşınabilir? – chux

cevap

2

Tamam, bir çekim yapalım: çok ayrıntılı görünümlü digit2int() işlevi her zaman güzel olan ASCII bağımlı olmamak için çalışıyor

#include <ctype.h> 
#include <stdio.h> 

static unsigned char hexdigit2int(unsigned char xd) 
{ 
    if (xd <= '9') 
    return xd - '0'; 
    xd = tolower(xd); 
    if (xd == 'a') 
    return 10; 
    if (xd == 'b') 
    return 11; 
    if (xd == 'c') 
    return 12; 
    if (xd == 'd') 
    return 13; 
    if (xd == 'e') 
    return 14; 
    if (xd == 'f') 
    return 15; 
    return 0; 
} 

int main(void) 
{ 
    const char st[] = "48656C6C6F3B", *src = st; 
    char text[sizeof st + 1], *dst = text; 

    while (*src != '\0') 
    { 
    const unsigned char high = hexdigit2int(*src++); 
    const unsigned char low = hexdigit2int(*src++); 
    *dst++ = (high << 4) | low; 
    } 
    *dst = '\0'; 
    printf("Converted '%s', got '%s'\n", st, text); 
    return 0; 
} 

. main()'daki döngünün doğru girişi aldığını, yalnızca her iki karakter için sonlandırmayı kontrol ettiğini ve onaltılık olmayan verileri işlemeyeceğini unutmayın.

Oh, ve bu baskılar:

Converted '48656C6C6F3B', got 'Hello;' 
+0

@chux Elbette, neden olmasın. Refactoring her şeyden önce hayattır. Halloldu teşekkür ederim. – unwind

0

Muhtemelen her bir character is represented by an int -> ... 'a' = 97, 'b' = 98 ... bildiğiniz gibi, bir hex'i int'ye dönüştürdüğünüzde, onu başka bir işleve dönüştürmeye gerek yoktur. - Tamsayı bir karaktere saklamak, hile yapacaktır (egzersizi anlayan bir şeyi kaçırmadığı sürece). belleğe geri depolamak için olduğu gibi

: birçok seçenek vardır: 1.

bakmak sscanf istenilen hücreye fonksiyonun geri dönüş değerini atamak veya kullanan const char st[12] = "48656C6C6F3B"; ve önce const kaldırmak here

0

Her şeyi iyi yaptınız, ancak bazı sorunlar var. Aşağıdaki ile karşılaştırın:

const char* st = "48656C6C6F3B"; // I don't want to calculate storage size 
char r[12] = { 0 }; // Here is I want to store the result 
char* h = r; // pointer to write position in the result 
int length = strlen(st); 
for (int i = 0; i < length; i+=2) { 
    assert((h - r) < sizeof(r)); // check that there is not problem with out of range 
    *h++ = hex_to_ascii(st[i], st[i + 1]); 
} 
printf("%s", r); // now the r contains "ansi string" 
0

sonucu "kaydet" için, basit bir sonuç saklamak için, bir tampon, dest ekleyin.

Ek öneriler kodda bulunur. Alternatif olarak

// add void to signature 
int main(void) { 
    const char st[12] = "48656C6C6F3B"; 
    int length = strlen(st); 
    int i; 
    char buf = 0; 

    // add destination buffer 
    char dest[10]; 

    // Add test 
    // for (i = 0; i < length; i++) { 
    for (i = 0; i < length && (i/2 + 1) < sizeof(dest); i++) { 
    if (i % 2 != 0) { 

     // printf("%c", hex_to_ascii(buf, st[i])); 
     dest[i/2] = hex_to_ascii(buf, st[i]); 

    } else { 
     buf = st[i]; 
    } 
    } 

    // Add termination 
    dest[i/2] = '\0'; 
    // Do someting with dest 
    puts(dest); 
    return 0; 
} 

, çeşitli olası sorunları ele bazı kod:/küçük basamaklı hex, hatalı karakterlerin, tek sayısı, küçük bir tampon, gömülü sıfır karakteri.

#include <stdlib.h> 
#include <string.h> 
// There are _many_ ways to do this step. 
unsigned char2digit(int ch) { 
    static const char Hex[] = "ABCDEFabcdef"; 
    char *p = memchr(Hex, ch, 32); 
    if (p) { 
    return (unsigned) (p - Hex) % 16; 
    } 
    return (unsigned) -1; // error value 
} 

// Return NULL with ill-formed string 
char *HexStringToString(char *dest, size_t size, const char *src) { 
    char *p = dest; 
    if (size <= 0) { 
    return NULL; 
    } 
    size--; 
    while (*src) { 
    if (size == 0) return NULL; 
    size--; 

    unsigned msb = char2digit(*src++); 
    if (msb > 15) return NULL; 
    unsigned lsb = char2digit(*src++); 
    if (lsb > 15) return NULL; 
    char ch = (char) (msb * 16 + lsb); 

    // Optionally test for embedded null character 
    if (ch == 0) return NULL; 

    *p++ = ch; 
    } 
    *p = '\0'; 
    return dest; 
} 

void testHex(const char *s) { 
    char buf[10]; 
    char *dest = HexStringToString(buf, sizeof buf, s); 
    printf("%-24s --> '%s'\n", s, dest ? dest : "NULL"); 
} 

#include <stdio.h> 
int main(void) { 
    testHex("48656C6C6F3B");  // upper case 
    testHex("48656c6c6f3b");  // lower case 
    testHex(""); 
    testHex("48656C6C6F3B48656C"); 
    // fails 
    testHex("48656C6C6F3B48656C6C"); // Too long 
    testHex("48656C6C6F3B0");  // Odd character count 
    testHex("48656C6C6F3Bxx");  // Non-hex character 
    testHex("48006C6C6F3B");   // null character 
    return 0; 
}   

Çıkış

48656C6C6F3B    --> 'Hello;' 
48656c6c6f3b    --> 'Hello;' 
         --> '' 
48656C6C6F3B48656C  --> 'Hello;Hel' 
48656C6C6F3B48656C6C  --> 'NULL' 
48656C6C6F3B0   --> 'NULL' 
48656C6C6F3Bxx   --> 'NULL' 
48006C6C6F3B    --> 'NULL'