Hex to char массив в C - PullRequest
       11

Hex to char массив в C

9 голосов
/ 13 октября 2009

С учетом строки шестнадцатеричных значений , т.е. например. «0011223344», то есть 0x00, 0x11 и т. Д.

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

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

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

Ответы [ 10 ]

17 голосов
/ 13 октября 2009

Вы не можете поместить данные размером 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);
}

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

3 голосов
/ 13 октября 2009

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

// 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;
}
3 голосов
/ 13 октября 2009

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

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

РЕДАКТИРОВАТЬ 1: извините, я забыл рассчитать с буквами A-F (a-f)

РЕДАКТИРОВАТЬ 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;
}

Тестирование:

#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" )
1 голос
/ 27 ноября 2014

Допустим, это платформа ascii с прямым порядком байтов. Может быть, OP означало «массив символов», а не «строка» .. Мы работаем с парами символов и битовых маскировок. Обратите внимание на смещение 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));
 }

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

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

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

1 голос
/ 13 августа 2014

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

// 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 голосов
/ 22 мая 2019

Лучший способ, которым я знаю:

int hex2bin_by_zibri(char *source_str, char *dest_buffer)
{
  char *line = source_str;
  char *data = line;
  int offset;
  int read_byte;
  int data_len = 0;

  while (sscanf(data, " %02x%n", &read_byte, &offset) == 1) {
    dest_buffer[data_len++] = read_byte;
    data += offset;
  }
  return data_len;
}

Функция возвращает количество преобразованных байтов, сохраненных в dest_buffer. Входная строка может содержать пробелы и буквы в смешанном регистре.

"01 02 03 04 ab Cd eF мусор AB"

переводится в dest_buffer, содержащий 01 02 03 04 ab cd ef

а также "01020304abCdeFgarbageAB"

переводится как и раньше.

Синтаксический анализ останавливается при первой «ошибке» (не шестнадцатеричный, не пробельный)

Примечание: также это допустимая строка:

"01 2 03 04 ab Cd eF фигня AB"

и производит:

01 02 03 04 ab cd ef

0 голосов
/ 21 февраля 2013
{
    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 голосов
/ 13 октября 2009

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

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

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

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

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

сделано.

Примечания: Для преобразования длинной строки в 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 голосов
/ 13 октября 2009

Fatalfloor ...

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

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

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

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

Сохранить int в массиве символов?

0 голосов
/ 13 октября 2009

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

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

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

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

...