Hex to char массив в C

Given a string of hex values i.e. e.g. "0011223344" so that's 0x00, 0x11 etc.

How do I add these values to a char array?

Equivalent to say:

char array[4] = { 0x00, 0x11 ... };
12.10.2009 22:59:28
10 ОТВЕТОВ

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

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

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

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

-4
21.02.2013 16:20:27
It's not a std::string - this is C and there's only one sort of string.
Jonathan Leffler 12.10.2009 23:12:00
@Paul: what do you consider is useful about your answer? The question is about 'how to walk through the input and assign it to an array'...which you carefully leave as an exercise for the reader.
Jonathan Leffler 12.10.2009 23:13:29
@jon: (1)C & C++ get confused sometimes, (2)I leave homework questions as exercises to the asker, typically, and (3)I was expecting responses from the OP so as to hone in on giving a better answer, but he did an "ask and run".
Paul Nathan 13.10.2009 12:41:31

You can't fit 5 bytes worth of data into a 4 byte array; that leads to buffer overflows.

If you have the hex digits in a string, you can use sscanf() and a loop:

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

Note that printing the string starting with a zero-byte requires care; most operations terminate on the first null byte. Note that this code did not null-terminate the buffer; it is not clear whether null-termination is desirable, and there isn't enough space in the buffer I declared to add a terminal null (but that is readily fixed). There's a decent chance that if the code was packaged as a subroutine, it would need to return the length of the converted string (though you could also argue it is the length of the source string divided by two).

18
13.10.2009 02:39:13
This answer saved me HOURS!!! of work. Works great for Arduino as well, just omit the printf section
frazras 18.07.2012 21:53:12

If the string is correct and no need to keep its content then i would do it this way:

#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: sorry, i forget to calculate with the letters A-F (a-f)

EDIT 2: i tried to write a more pedantic code:

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

Result:

 -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" )
3
13.10.2009 02:34:28
This assumes you are allowed to modify the string, and does the translation in situ, and null terminates the converted string. Since the first byte is null, you probably need to return the number of converted characters.
Jonathan Leffler 12.10.2009 23:32:45
You are true, but the question does not formulate requirements, so this code is good enough ;-)
sambowry 12.10.2009 23:40:42
You might want to consider supporting hex digits above 9, too. If the only string required to work is the one given in the question, then obviously the most concise answer is char array[] = {0, 17, 34, 51, 68};. But I think when the questioner said "i.e.", he actually meant "e.g."
Steve Jessop 12.10.2009 23:42:30

Fatalfloor...

There are a couple of ways to do this... first, you can use memcpy() to copy the exact representation into the char array.

You can use bit shifting and bit masking techniques as well. I'm guessing this is what you need to do as it sounds like a homework problem.

Lastly, you can use some fancy pointer indirection to copy the memory location you need.

All of these methods are detailed here:

Store an int in a char array?

0
23.05.2017 11:46:14
Не могли бы вы уточнить, как можно использовать memcpy ()?
Jonathan Leffler 13.10.2009 02:43:18

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

// 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.10.2009 02:18:35

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

Hex string to numeric value , i.e. str[] = "0011223344" to value 0x0011223344, use

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

done. if need remove beginning 0x00, see below.

though for LITTLE_ENDIAN platforms, plus: Hex value to char array, value 0x11223344 to 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));

done.

Notes: For converting long string to a 64 bits hex char arr on a 32-bit system, you should use unsigned long long instead of unsigned long, and htonl is not enough, so do it yourself as below because might there's no htonll, htonq or 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)

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

0
13.10.2009 02:54:11
поддерживаемая максимальная длина шестнадцатеричной строки: 16 байтов / символов, когда начальный символ не равен 0.
Test 13.10.2009 03:02:40
{
    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
21.02.2013 16:11:07

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

// 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);
}
1
13.08.2014 11:52:28

Допустим, это платформа 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
4.02.2015 22:31:53
Можете ли вы объяснить, как вы знаете hex(0x30,0x57,0x37)этот процесс извлечения?
Faruk 28.02.2019 13:05:51
Для ASCII они являются смежными (это не будет работать для EBCDIC и потребует дополнительных тестов.) Обратитесь к любой таблице ASCII. «0» равно 48. Вычитание 48 из «0» (символ) дает 0 (целое число). 48 - это 0x30 (3x16) + (0x1). Да, они должны иметь десятичное значение. Извините. Если бы я был очень ленив, я бы просто использовал unhex () из MySQL или использовал этот источник.
mckenzm 28.02.2019 22:22:28

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

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 garbage AB"

translates to dest_buffer containing 01 02 03 04 ab cd ef

and also "01020304abCdeFgarbageAB"

translates as before.

Parsing stops at the first "error" (non hex, non space).

Note: also this is a valid string:

"01 2 03 04 ab Cd eF garbage AB"

and produces:

01 02 03 04 ab cd ef

0
22.05.2019 00:03:56