在C语言中将十六进制字符串转换为字节数组

68

有没有标准的C函数可以将十六进制字符串转换为字节数组
我不想自己编写函数。


1
你的意思是一个包含表示十六进制数字的字符的字符串吗? - Nate
1
是的,我有用户输入字符串,例如“abCD12ff34”,长度大于等于0,我想将其转换为字节数组,如0xaa、0xcd、0x12等。 - Szere Dyeri
22个回答

1
char *hexstring = "deadbeef10203040b00b1e50", *pos = hexstring;
unsigned char val[12];
while( *pos )
{
  if( !((pos-hexstring)&1) )
    sscanf(pos,"%02x",&val[(pos-hexstring)>>1]);
  ++pos;
}

sizeof(val)/sizeof(val[0])是多余的!


这会写入缓冲区末尾之外的位置!另外,只需使用 p+=2 而不是 &1 检查。 - mafu
1
unsigned char val[12];...sscanf(pos,"%02x",&val[...]); 是错误的,因为它试图将一个 unsigned 存储到一个 unsigned char 中。 - chux - Reinstate Monica

1

这是从一个类似的问题修改的函数,根据https://dev59.com/M3XYa4cB1Zd3GeqP98AA#18267932的建议进行了修改。

此函数将把具有偶数个字符的十六进制字符串(不带前缀“0x”)转换为指定字节数的数字。如果遇到无效字符或十六进制字符串长度为奇数,则返回-1;成功则返回0。

//convert hexstring to len bytes of data
//returns 0 on success, -1 on error
//data is a buffer of at least len bytes
//hexstring is upper or lower case hexadecimal, NOT prepended with "0x"
int hex2data(unsigned char *data, const unsigned char *hexstring, unsigned int len)
{
    unsigned const char *pos = hexstring;
    char *endptr;
    size_t count = 0;

    if ((hexstring[0] == '\0') || (strlen(hexstring) % 2)) {
        //hexstring contains no data
        //or hexstring has an odd length
        return -1;
    }

    for(count = 0; count < len; count++) {
        char buf[5] = {'0', 'x', pos[0], pos[1], 0};
        data[count] = strtol(buf, &endptr, 0);
        pos += 2 * sizeof(char);

        if (endptr[0] != '\0') {
            //non-hexadecimal character encountered
            return -1;
        }
    }

    return 0;
}

1
    In main()
    {
printf("enter string :\n");
    fgets(buf, 200, stdin);
unsigned char str_len = strlen(buf);
k=0;
unsigned char bytearray[100];
     for(j=0;j<str_len-1;j=j+2)
        { bytearray[k++]=converttohex(&buffer[j]);   
                printf(" %02X",bytearray[k-1]);
        }

    }

    Use this 

    int converttohex(char * val)
        {
        unsigned char temp = toupper(*val);
        unsigned char fin=0;
        if(temp>64)
        temp=10+(temp-65);

        else
        temp=temp-48;

        fin=(temp<<4)&0xf0;

        temp = toupper(*(val+1));

            if(temp>64)
            temp=10+(temp-65);

            else
            temp=temp-48;

        fin=fin|(temp & 0x0f);


           return fin;
        }

1

使用strchr()解析字节或字的两个简短例程。

// HexConverter.h
#ifndef HEXCONVERTER_H
#define HEXCONVERTER_H
unsigned int hexToByte (const char *hexString);
unsigned int hexToWord (const char *hexString);
#endif


// HexConverter.c
#include <string.h> // for strchr()
#include <ctype.h>  // for toupper()

unsigned int hexToByte (const char *hexString)
{
    unsigned int value;
    const char *hexDigits = "0123456789ABCDEF";

    value = 0;
    if (hexString != NULL)
    {
        char *ptr;

        ptr = strchr (hexDigits, toupper(hexString[0]));
        if (ptr != NULL)
        {
            value = (ptr - hexDigits) << 4;

            ptr = strchr (hexDigits, toupper(hexString[1]));
            if (ptr != NULL)
            {
                value = value | (ptr - hexDigits);
            }
        }
    }

    return value;
}

unsigned int hexToWord (const char *hexString)
{
    unsigned int value;

    value = 0;
    if (hexString != NULL)
    {
        value = (hexToByte (&hexString[0]) << 8) |
                (hexToByte (&hexString[2]));
    }

    return value;
}


// HexConverterTest.c
#include <stdio.h>

#include "HexConverter.h"

int main (int argc, char **argv)
{
    (void)argc; // not used
    (void)argv; // not used

    unsigned int value;
    char *hexString;

    hexString = "2a";
    value = hexToByte (hexString);
    printf ("%s == %x (%u)\n", hexString, value, value);

    hexString = "1234";
    value = hexToWord (hexString);
    printf ("%s == %x (%u)\n", hexString, value, value);

    hexString = "0102030405060708090a10ff";
    printf ("Hex String: %s\n", hexString);
    for (unsigned int idx = 0; idx < strlen(hexString); idx += 2)
    {
        value = hexToByte (&hexString[idx]);
        printf ("%c%c == %x (%u)\n", hexString[idx], hexString[idx+1],
                value, value);
    }

    return EXIT_SUCCESS;
}


0

它可能更简单吗?!

uint8_t hex(char ch) {
    uint8_t r = (ch > 57) ? (ch - 55) : (ch - 48);
    return r & 0x0F;
}

int to_byte_array(const char *in, size_t in_size, uint8_t *out) {
    int count = 0;
    if (in_size % 2) {
        while (*in && out) {
            *out = hex(*in++);
            if (!*in)
                return count;
            *out = (*out << 4) | hex(*in++);
            *out++;
            count++;
        }
        return count;
    } else {
        while (*in && out) {
            *out++ = (hex(*in++) << 4) | hex(*in++);
            count++;
        }
        return count;
    }
}

int main() {
    char hex_in[] = "deadbeef10203040b00b1e50";
    uint8_t out[32];
    int res = to_byte_array(hex_in, sizeof(hex_in) - 1, out);

    for (size_t i = 0; i < res; i++)
        printf("%02x ", out[i]);

    printf("\n");
    system("pause");
    return 0;
}

0

这是我的版本:

/* Convert a hex char digit to its integer value. */
int hexDigitToInt(char digit) {
    digit = tolower(digit);
    if ('0' <= digit && digit <= '9') //if it's decimal
        return (int)(digit - '0');
    else if ('a' <= digit && digit <= 'f') //if it's abcdef
        return (int)(digit - ('a' - 10));
    else
        return -1; //value not in [0-9][a-f] range
}

/* Decode a hex string. */
char *decodeHexString(const char *hexStr) {
    char* decoded = malloc(strlen(hexStr)/2+1);
    char* hexStrPtr = (char *)hexStr;
    char* decodedPtr = decoded;

    while (*hexStrPtr != '\0') { /* Step through hexStr, two chars at a time. */
        *decodedPtr = 16 * hexDigitToInt(*hexStrPtr) + hexDigitToInt(*(hexStrPtr+1));
        hexStrPtr += 2;
        decodedPtr++;
    }

    *decodedPtr = '\0'; /* final null char */
    return decoded;
}

你在*(decodedPtr+1) = '\0'中出现了一个美丽的“越界一个”的错误(因为在上次写入后decodedPtr已经被增加了)。 - rluba

0
尝试以下代码:
static unsigned char ascii2byte(char *val)
{
    unsigned char temp = *val;

    if(temp > 0x60) temp -= 39;  // convert chars a-f
    temp -= 48;  // convert chars 0-9
    temp *= 16;

    temp += *(val+1);
    if(*(val+1) > 0x60) temp -= 39;  // convert chars a-f
    temp -= 48;  // convert chars 0-9   

    return temp;

}

0

对于新手和为了改进@Michael的答案,这里提供完整版本:

// out needs to be at least len/2+1 bytes long
// length will be returned 
int hexStrToBin(char* out, const char *str)
{
    int i, len = strlen(str);

    for (i = 0; i < len; i++)
    {
        // Reads str & stores in op
        sscanf(str, "%2hhx", &op[i]);
        str += 2;
    }

    return len/2;
}

该函数返回一个指向堆栈分配的数组(op)的引用,可能导致未定义的行为。 - Thom Wiggers
@ThomWiggers,你能指出这里有什么问题吗?我有一个函数可以解决我的任务。 - Daniel Selvan
1
op 在栈上分配,当 hexStrToBin 返回后就会停止存在。虽然这个答案是关于 C++ 的,但在这里同样适用 https://dev59.com/Rm445IYBdhLWcg3w6eNo#30864512。 - Thom Wiggers
我已进行编辑以消除UB。 - Thom Wiggers
我认为修改应该将&op[i]改为&out[i]。根据我现在的阅读,op未定义。 - Andrew Falanga

0
/**
 * @brief Convert a hex string to a byte array
 * @param hex pointer to the hex string to convert
 * @param output Array to place the results, should be half the size of the input array
 * @param array_length Number of bytes to output
 */
void hex_to_bytes(char *hex, uint8_t *output, uint8_t array_length)
{
    for (int i = 0, j = 0; i < array_length; i++, j += 2)
    {
        hex[j] = toupper(hex[j]);
        hex[j+1] = toupper(hex[j+1]);

        uint8_t bottom = hex[j + 1] - (hex[j + 1] > '9' ? 'A' - 10 : '0');
        uint8_t top = hex[j] - (hex[j] > '9' ? 'A' - 10 : '0');
        output[i] = (top * 16) + bottom;
    }
}

-1

不是。但是使用循环中的sscanf相对容易实现。


1
任何在SO上的问题都不应该有“琐碎”的回答,否则这个问题就没有存在的意义。 - Valerio
显然奥利弗不知道,否则他就会在答案中发表这个“平凡”的循环 :) - Zibri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接