简体   繁体   English

C中的十六进制到字符数组

[英]Hex to char array in C

Given a string of hex values ie eg "0011223344" so that's 0x00, 0x11 etc.给定一串十六进制值,例如“0011223344”,0x00、0x11 等。

How do I add these values to a char array?如何将这些值添加到字符数组?

Equivalent to say:相当于说:

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

You can't fit 5 bytes worth of data into a 4 byte array;您不能将 5 个字节的数据放入 4 个字节的数组中; that leads to buffer overflows.这会导致缓冲区溢出。

If you have the hex digits in a string, you can use sscanf() and a loop:如果字符串中有十六进制数字,则可以使用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);
}

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).如果将代码打包为子例程,则很有可能需要返回转换后的字符串的长度(尽管您也可以认为它是源字符串的长度除以二)。

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 AF (af)编辑 1:对不起,我忘记用字母 AF (af) 计算

EDIT 2: i tried to write a more pedantic code:编辑 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 );
}

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

I would do something like this;我会做这样的事情;

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

I was searching for the same thing and after reading a lot, finally created this function.我一直在寻找同样的东西,在阅读了很多之后,终于创建了这个函数。 Thought it might help, someone认为它可能会有所帮助,有人

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

Let's say this is a little-endian ascii platform.假设这是一个 little-endian ascii 平台。 Maybe the OP meant "array of char" rather than "string".. We work with pairs of char and bit masking.. note shiftyness of x16..也许 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));
 }

and function encode() is defined...并定义了函数 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);
}

This approach floats around elsewhere, it is not my original work, but it is old.这种方法在别处飘荡,不是我的原创,但它是旧的。 Not liked by the purists because it is non-portable, but extension would be trivial.纯粹主义者不喜欢它,因为它不可移植,但扩展是微不足道的。

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

Fatalfloor...致命的地板...

There are a couple of ways to do this... first, you can use memcpy() to copy the exact representation into the char array.有几种方法可以做到这一点......首先,您可以使用 memcpy() 将确切的表示复制到 char 数组中。

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? 将 int 存储在 char 数组中?

Give a best way:给个最好的办法:

Hex string to numeric value , ie str[] = "0011223344" to value 0x0011223344, use十六进制字符串到数值,即 str[] = "0011223344" 到值 0x0011223344,使用

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

done.完毕。 if need remove beginning 0x00, see below.如果需要删除开头的 0x00,请参见下文。

though for LITTLE_ENDIAN platforms, plus: Hex value to char array, value 0x11223344 to char arr[N] = {0x00, 0x11, ...}虽然对于 LITTLE_ENDIAN 平台,加上:十六进制值到字符数组,值 0x11223344 到字符 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:注意:在 32 位系统上要将长字符串转换为 64 位十六进制字符 arr,您应该使用 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)

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

The best way I know:我所知道的最好方法:

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

The function returns the number of converted bytes saved in dest_buffer.该函数返回保存在 dest_buffer 中的转换字节数。 The input string can contain spaces and mixed case letters.输入字符串可以包含空格和大小写混合的字母。

"01 02 03 04 ab Cd eF garbage AB" “01 02 03 04 ab Cd eF 垃圾 AB”

translates to dest_buffer containing 01 02 03 04 ab cd ef转换为包含 01 02 03 04 ab cd ef 的 dest_buffer

and also "01020304abCdeFgarbageAB"还有“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" “01 2 03 04 ab Cd eF 垃圾 AB”

and produces:并产生:

01 02 03 04 ab cd ef 01 02 03 04 ab cd ef

Below are my hex2bin and bin2hex implementations.下面是我的hex2binbin2hex实现。

These functions:这些功能:

  • Are public domain (feel free to copy and paste)是公共领域(随意复制和粘贴)
  • Are simple很简单
  • Are correct (ie, tested)是正确的(即,经过测试)
  • Perform error handling ( -1 means invalid hex string)执行错误处理( -1表示无效的十六进制字符串)

hex2bin hex2bin

static char h2b(char c) {
    return '0'<=c && c<='9' ? c - '0'      :
           'A'<=c && c<='F' ? c - 'A' + 10 :
           'a'<=c && c<='f' ? c - 'a' + 10 :
           /* else */         -1;
}

int hex2bin(unsigned char* bin,  unsigned int bin_len, const char* hex) {
    for(unsigned int i=0; i<bin_len; i++) {
        char b[2] = {h2b(hex[2*i+0]), h2b(hex[2*i+1])};
        if(b[0]<0 || b[1]<0) return -1;
        bin[i] = b[0]*16 + b[1];
    }
    return 0;
}

bin2hex bin2hex

static char b2h(unsigned char b, int upper) {
    return b<10 ? '0'+b : (upper?'A':'a')+b-10;
}

void bin2hex(char* hex, const unsigned char* bin, unsigned int bin_len, int upper) {
    for(unsigned int i=0; i<bin_len; i++) {
        hex[2*i+0] = b2h(bin[i]>>4,   upper);
        hex[2*i+1] = b2h(bin[i]&0x0F, upper);
    }
}

First, your question isn't very precise.首先,你的问题不是很准确。 Is the string a std::string or a char buffer?字符串是std::string还是char缓冲区? Set at compile-time?在编译时设置?

Dynamic memory is almost certainly your answer.动态记忆几乎肯定是您的答案。

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

Then, you can walk through the input, and assign it to the array.然后,您可以遍历输入,并将其分配给数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM