2009-10-12 6 views
6

Указанная строка шестнадцатеричных значений i.e., например. «0011223344», так что это 0x00, 0x11 и т. Д.Hex to char array в C

Как добавить эти значения в массив символов?

Эквивалент сказать:

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

ответ

-3

Во-первых, ваш вопрос не очень точным. Строка a std::string или буфер char? Установлено во время компиляции?

Динамическая память - это почти наверняка ваш ответ.

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

Затем вы можете пройти через вход и назначить его массиву.

+1

Это не std :: string - это C, и есть только одна разновидность строки. –

+2

@Paul: что вы считаете полезным в своем ответе? Вопрос в том, «как пройти через вход и назначить его массиву» ... который вы тщательно оставляете в качестве упражнения для читателя. –

+1

@jon: (1) Иногда C & C++ иногда путается, (2) Я оставляю домашние задания как упражнения для искателя, как правило, и (3) Я * ожидал * ответов от OP, чтобы оттолкнуть лучший ответ, но он «попросил и бежал». –

16

Вы не можете вместить 5 байт данных в 4-байтовый массив; что приводит к переполнению буфера.

Если у вас есть шестнадцатеричные цифры в строке, вы можете использовать sscanf() и цикл:

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

Обратите внимание, что печать строки, начиная с нулевым байтом требует ухода; большинство операций заканчиваются на первом нулевом байте. Обратите внимание, что этот код не завершал нуль буфера; неясно, является ли нулевое завершение желательным, и не хватает места в буфере, который я объявил, чтобы добавить терминал null (но это легко фиксируется). Есть неплохая вероятность, что если код был упакован как подпрограмма, ему нужно будет вернуть длину преобразованной строки (хотя вы также можете утверждать, что длина исходной строки делится на две).

+2

Этот ответ спас меня ЧАСЫ !!! работы. Отлично подходит для Arduino, просто опустите раздел printf. – frazras

3

Если строка не является правильным, и нет необходимости держать его содержание, то я хотел бы сделать это таким образом:

#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: извините, я забыл вычислить с буквами AF (AF)

EDIT 2: я попытался написать более педантичный код:

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

Testing:

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

Результат:

-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

. Предполагается, что вам разрешено изменять строку и выполняется перевод на месте, а null завершает преобразованную строку. Поскольку первый байт имеет значение NULL, вам, вероятно, нужно вернуть число преобразованных символов. –

+0

Вы правдивы, но вопрос не формулирует требования, поэтому этот код достаточно хорош ;-) – sambowry

+0

Возможно, вам стоит подумать о поддержке шестнадцатеричных цифр выше 9.Если единственной строкой, требуемой для работы, является та, которая задана в вопросе, то, очевидно, наиболее кратким ответом является 'char array [] = {0, 17, 34, 51, 68};'. Но я думаю, что когда вопроситель сказал «т. Е.», Он на самом деле имел в виду «например». –

0

Fatalfloor ...

Есть несколько способов сделать это ... первый, вы можете использовать тетср(), чтобы скопировать точное представление в массив символов.

Вы также можете использовать методы смены битов и методы маскировки бит. Я предполагаю, что это то, что вам нужно сделать, поскольку это звучит как проблема домашних заданий.

Наконец, вы можете использовать некоторую косвенную направленность указателя, чтобы скопировать нужную ячейку памяти.

Все эти методы подробно описаны здесь:

Store an int in a char array?

+0

Не могли бы вы объяснить, как можно использовать memcpy()? –

3

Я хотел бы сделать что-то вроде этого;

// 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

Дайте лучший способ:

Hex строку числового значения, т.е. Обл [] = "0011223344" ценить 0x0011223344, используйте

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

сделано. если необходимо удалить начало 0x00, см. ниже.

хотя для LITTLE_ENDIAN платформ, плюс: шестнадцатеричное значение, чтобы массив символов, значение 0x11223344 на символ обр [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)); 

сделано.

Примечания: Для преобразования длинной строки в 64-разрядный шестнадцатеричный char в 32-разрядную систему вы должны использовать unsigned long long вместо unsigned long, а htonl недостаточно, так что сделайте это сами, как показано ниже, потому что может нет htonll, htonq или hton64 и т.д.:

#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) 

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

+0

поддерживается максимальная длина шестнадцатеричной строки: 16 байт/символов, когда начало символа не равно 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

Я искал то же самое и после того, как много читать, наконец, создал эту функцию. Подумал, что это может помочь, кто-то

// 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

Предположим, что это платформа на основе little-endian ascii. Возможно ОП означает «массив полукокса», а не «строка» .. Мы работаем с парами полукокса и бит маскирования .. примечание shiftyness из х16 ..

/* 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)); 
} 

и функция кодирования() определена. ..

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

Этот подход плывет вокруг в другом месте, это не моя оригинальная работа, но она старая. Не нравится пуристам, потому что он не переносится, но расширение будет тривиальным.