2009-10-12 11 views
6

Podany łańcuch wartości szesnastkowych , np. np. "0011223344", czyli 0x00, 0x11 itd.Hex do tablicy char w C

Jak dodać te wartości do tablicy char?

Odpowiednik powiedzieć:

char array[4] = { 0x00, 0x11 ... }; 

Odpowiedz

-3

Po pierwsze, pytanie nie jest bardzo precyzyjne. Czy ciąg znaków to bufor std::string lub char? Ustaw na czas kompilacji?

Pamięć dynamiczna to prawie na pewno Twoja odpowiedź.

char* arr = (char*)malloc(numberOfValues); 

Następnie można przejść przez dane wejściowe i przypisać je do tablicy.

+1

To nie jest std :: string - to C i jest tylko jeden rodzaj ciągu. –

+2

@Paul: Co sądzisz o twojej odpowiedzi? Pytanie brzmi: "jak przejść przez dane wejściowe i przypisać je do tablicy" ... które ostrożnie zostawiasz jako ćwiczenie dla czytelnika. –

+1

@jon: (1) C & C++ wprawiać w zakłopotanie czasami, (2) zostawiam pytania domowe jako ćwiczenia dla pytającego, zazwyczaj i (3) * oczekiwałem * odpowiedzi z PO, tak aby udoskonalić lepiej odpowiedzieć, ale wykonał polecenie "poproś i uciekaj". –

16

Nie można dopasować danych o wielkości 5 bajtów do 4-bajtowej tablicy; co prowadzi do przepełnienia bufora.

Jeśli masz cyfry szesnastkowe w ciąg, można użyć sscanf() i pętlę:

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

int main() 
{ 
    const char *src = "0011223344"; 
    char buffer[5]; 
    char *dst = buffer; 
    char *end = buffer + sizeof(buffer); 
    unsigned int u; 

    while (dst < end && sscanf(src, "%2x", &u) == 1) 
    { 
     *dst++ = u; 
     src += 2; 
    } 

    for (dst = buffer; dst < end; dst++) 
     printf("%d: %c (%d, 0x%02x)\n", dst - buffer, 
       (isprint(*dst) ? *dst : '.'), *dst, *dst); 

    return(0); 
} 

Zauważ, że drukowanie ciąg rozpoczynający się zero-bajt wymaga opieki; większość operacji kończy się na pierwszym bajcie zerowym. Zauważ, że ten kod nie zerwał bufora; nie jest jasne, czy pożądane jest zakończenie zerowe, a w buforze I zadeklarowałem brak miejsca na terminalu (ale to można łatwo ustalić). Istnieje spora szansa, że ​​jeśli kod został spakowany jako podprogram, musiałby zwrócić długość przekonwertowanego ciągu znaków (chociaż można również argumentować, że długość łańcucha źródłowego jest podzielona przez dwa).

+2

Ta odpowiedź uratowała mnie GODZINY !!! pracy. Działa również świetnie dla Arduino, po prostu pomiń sekcję printf. – frazras

3

Jeśli ciąg jest prawidłowy i nie ma potrzeby, aby utrzymać swoją zawartość następnie chciałbym zrobić to w ten sposób:

#define hex(c) ((*(c)>='a')?*(c)-'a'+10:(*(c)>='A')?*(c)-'A'+10:*(c)-'0') 

void hex2char(char *to){ 
    for(char *from=to; *from; from+=2) *to++=hex(from)*16+hex(from+1); 
    *to=0; 
} 

EDIT 1: przepraszam, nie pamiętam, aby obliczyć z literami AF (AF)

EDIT 2: starałem się napisać kod bardziej pedantyczny:

#include <string.h> 

int xdigit(char digit){ 
    int val; 
     if('0' <= digit && digit <= '9') val = digit -'0'; 
    else if('a' <= digit && digit <= 'f') val = digit -'a'+10; 
    else if('A' <= digit && digit <= 'F') val = digit -'A'+10; 
    else         val = -1; 
    return val; 
} 

int xstr2str(char *buf, unsigned bufsize, const char *in){ 
    if(!in) return -1; // missing input string 

    unsigned inlen=strlen(in); 
    if(inlen%2 != 0) return -2; // hex string must even sized 

    for(unsigned i=0; i<inlen; i++) 
    if(xdigit(in[i])<0) return -3; // bad character in hex string 

    if(!buf || bufsize<inlen/2+1) return -4; // no buffer or too small 

    for(unsigned i=0,j=0; i<inlen; i+=2,j++) 
    buf[j] = xdigit(in[i])*16 + xdigit(in[i+1]); 

    buf[inlen/2] = '\0'; 
    return inlen/2+1; 
}

Testowanie:

#include <stdio.h> 

char buf[100] = "test"; 

void test(char *buf, const char *s){ 
    printf("%3i=xstr2str(\"%s\", 100, \"%s\")\n", xstr2str(buf, 100, s), buf, s); 
} 

int main(){ 
    test(buf,  (char*)0 ); 
    test(buf,  "123"  ); 
    test(buf,  "3x"  ); 
    test((char*)0, ""  ); 
    test(buf,  ""  ); 
    test(buf,  "3C3e" ); 
    test(buf,  "3c31323e"); 

    strcpy(buf, "616263" ); test(buf, buf); 
}

Wynik:

-1=xstr2str("test", 100, "(null)") 
-2=xstr2str("test", 100, "123") 
-3=xstr2str("test", 100, "3x") 
-4=xstr2str("(null)", 100, "") 
    1=xstr2str("", 100, "") 
    3=xstr2str("", 100, "3C3e") 
    5=xstr2str("", 100, "3c31323e") 
    4=xstr2str("abc", 100, "abc") 
+0

Zakłada to, że możesz modyfikować ciąg znaków i wykonuje tłumaczenie na miejscu, a null kończy skonwertowany ciąg. Ponieważ pierwszy bajt ma wartość null, prawdopodobnie musisz zwrócić liczbę skonwertowanych znaków. –

+0

Jesteś prawdą, ale pytanie nie formułuje wymagań, więc ten kod jest wystarczająco dobry ;-) – sambowry

+0

Możesz także rozważyć wspieranie cyfr szesnastkowych powyżej 9.Jeśli jedynym ciągiem wymaganym do pracy jest ten podany w pytaniu, to oczywiście najbardziej zwięzłą odpowiedzią jest 'char array [] = {0, 17, 34, 51, 68};'. Ale myślę, że kiedy pytający powiedział "to znaczy", miał na myśli "np." –

0

Fatalfloor ...

Istnieje kilka sposobów, aby to zrobić ... po pierwsze, można użyć memcpy(), aby skopiować dokładną reprezentację do tablicy char.

Można również zastosować techniki zmiany bitów i bitowania. Zgaduję, że to jest to, co musisz zrobić, ponieważ brzmi to jak zadanie domowe.

Na koniec możesz użyć jakiegoś wymyślnego wskaźnika w celu skopiowania potrzebnej lokalizacji pamięci.

Wszystkie te metody są opisane tutaj:

Store an int in a char array?

+0

Czy chciałbyś wyjaśnić, w jaki sposób można użyć memcpy()? –

3

chciałbym zrobić coś takiego;

// Convert from ascii hex representation to binary 
// Examples; 
// "00" -> 0 
// "2a" -> 42 
// "ff" -> 255 
// Case insensitive, 2 characters of input required, no error checking 
int hex2bin(const char *s) 
{ 
    int ret=0; 
    int i; 
    for(i=0; i<2; i++) 
    { 
     char c = *s++; 
     int n=0; 
     if('0'<=c && c<='9') 
      n = c-'0'; 
     else if('a'<=c && c<='f') 
      n = 10 + c-'a'; 
     else if('A'<=c && c<='F') 
      n = 10 + c-'A'; 
     ret = n + ret*16; 
    } 
    return ret; 
} 

int main() 
{ 
    const char *in = "0011223344"; 
    char out[5]; 
    int i; 

    // Hex to binary conversion loop. For example; 
    // If in="0011223344" set out[] to {0x00,0x11,0x22,0x33,0x44} 
    for(i=0; i<5; i++) 
    { 
     out[i] = hex2bin(in); 
     in += 2; 
    } 
    return 0; 
} 
0

Daj najlepszy sposób:

HEX do wartości numerycznej, to znaczy ul [] = "0011223344" osiągnięcie korzyści 0x0011223344 użyć

value = strtoul(string, NULL, 16); // or strtoull() 

wykonane. w razie potrzeby usuń początek 0x00, patrz poniżej.

chociaż platform LITTLE_ENDIAN oraz: Wartość Hex char macierz, wartość 0x11223344 char arr [n] = {0x00, 0x11, ...}

unsigned long *hex = (unsigned long*)arr; 
*hex = htonl(value); 
// you'd like to remove any beginning 0x00 
char *zero = arr; 
while (0x00 == *zero) { zero++; } 
if (zero > arr) memmove(zero, arr, sizeof(arr) - (zero - arr)); 

wykonane.

Notatki: Aby przekonwertować długi ciąg na 64-bitowy znak szesnastkowy w systemie 32-bitowym, należy użyć unsigned long long zamiast unsigned long, a htonl to za mało, zrób to sam, jak poniżej, ponieważ może nie ma htonll, htonq lub hton64 etc:

#if __KERNEL__ 
    /* Linux Kernel space */ 
    #if defined(__LITTLE_ENDIAN_BITFIELD) 
     #define hton64(x) __swab64(x) 
    #else 
     #define hton64(x) (x) 
    #endif 
#elif defined(__GNUC__) 
    /* GNU, user space */ 
    #if __BYTE_ORDER == __LITTLE_ENDIAN 
     #define hton64(x) __bswap_64(x) 
    #else 
     #define hton64(x) (x) 
    #endif 
#elif 
     ... 
#endif 

#define ntoh64(x) hton64(x) 

zobaczyć http://effocore.googlecode.com/svn/trunk/devel/effo/codebase/builtin/include/impl/sys/bswap.h

+0

obsługiwana maksymalna długość łańcucha szesnastkowego: 16 bajtów/znaków, gdy początkiem char nie jest '0'. – Test

0
{ 
    char szVal[] = "268484927472"; 
    char szOutput[30]; 

    size_t nLen = strlen(szVal); 
    // Make sure it is even. 
    if ((nLen % 2) == 1) 
    { 
     printf("Error string must be even number of digits %s", szVal); 
    } 

    // Process each set of characters as a single character. 
    nLen >>= 1; 
    for (size_t idx = 0; idx < nLen; idx++) 
    { 
     char acTmp[3]; 
     sscanf(szVal + (idx << 1), "%2s", acTmp); 
     szOutput[idx] = (char)strtol(acTmp, NULL, 16); 
    } 
} 
0

szukałem tej samej rzeczy i po przeczytaniu wielu, w końcu stworzył tę funkcję. Pomyślałem, że może to pomóc, ktoś

// in = "63 09 58 81" 
void hexatoascii(char *in, char* out, int len){ 
    char buf[5000]; 
    int i,j=0; 
    char * data[5000]; 
    printf("\n size %d", strlen(in)); 
    for (i = 0; i < strlen(in); i+=2) 
    { 
     data[j] = (char*)malloc(8); 
     if (in[i] == ' '){ 
      i++; 
     } 
     else if(in[i + 1] == ' '){ 
      i++; 
     } 
     printf("\n %c%c", in[i],in[i+1]); 
     sprintf(data[j], "%c%c", in[i], in[i+1]); 
     j++; 
    } 

    for (i = 0; i < j-1; i++){ 
     int tmp; 
     printf("\n data %s", data[i]); 
     sscanf(data[i], "%2x", &tmp); 
     out[i] = tmp; 
    } 
    //printf("\n ascii value of hexa %s", out); 
} 
0

Powiedzmy, że jest to mało endian platforma ASCII. Może OP oznaczało „tablicę char” zamiast „ciąg” .. Współpracujemy z par char a bit maskowania .. uwaga shiftyness z x16 ..

/* not my original work, on stacko somewhere ? */ 

for (i=0;i < 4;i++) { 

    char a = string[2 * i]; 
    char b = string[2 * i + 1]; 

    array[i] = (((encode(a) * 16) & 0xF0) + (encode(b) & 0x0F)); 
} 

i funkcja kodowania() jest zdefiniowana. ..

unsigned char encode(char x) {  /* Function to encode a hex character */ 
/**************************************************************************** 
* these offsets should all be decimal ..x validated for hex..    * 
****************************************************************************/ 
    if (x >= '0' && x <= '9')   /* 0-9 is offset by hex 30 */ 
     return (x - 0x30); 
    else if (x >= 'a' && x <= 'f') /* a-f offset by hex 57 */ 
     return(x - 0x57); 
    else if (x >= 'A' && x <= 'F') /* A-F offset by hex 37 */ 
     return(x - 0x37); 
} 

Takie podejście pojawia się gdzie indziej, nie jest to moje oryginalne dzieło, ale jest stare. Nie lubiany przez purystów, ponieważ nie jest przenośny, ale rozszerzenie byłoby banalne.