C语言 如何在 C 中正确地将十六进制字符串转换为字节数组?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18267803/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 07:10:58  来源:igfitidea点击:

How to correctly convert a Hex String to Byte Array in C?

carraystype-conversion

提问by Alex

I need to convert a string, containing hex values as characters, into a byte array. Although this has been answered already hereas the first answer, I get the following error:

我需要将包含十六进制值作为字符的字符串转换为字节数组。虽然这里已经作为第一个答案回答这个问题,但我收到以下错误:

warning: ISO C90 does not support the ‘hh' gnu_scanf length modifier [-Wformat]

Since I do not like warnings, and the omission of hhjust creates another warning

因为我不喜欢警告,而省略hh只是造成另一个警告

warning: format ‘%x' expects argument of type ‘unsigned int *', but argument 3 has type ‘unsigned char *' [-Wformat]

my question is: How to do this right? For completion, I post the example code here again:

我的问题是:如何正确地做到这一点?为了完成,我再次在此处发布示例代码:

#include <stdio.h>

int main(int argc, char **argv)
{
    const char hexstring[] = "deadbeef10203040b00b1e50", *pos = hexstring;
    unsigned char val[12];
    size_t count = 0;

     /* WARNING: no sanitization or error-checking whatsoever */
    for(count = 0; count < sizeof(val)/sizeof(val[0]); count++) {
        sscanf(pos, "%2hhx", &val[count]);
        pos += 2 * sizeof(char);
    }

    printf("0x");
    for(count = 0; count < sizeof(val)/sizeof(val[0]); count++)
        printf("%02x", val[count]);
    printf("\n");

    return(0);
}

采纳答案by mvp

You can use strtol()instead.

你可以strtol()改用。

Simply replace this line:

只需替换此行:

sscanf(pos, "%2hhx", &val[count]);

with:

和:

char buf[10];
sprintf(buf, "0x%c%c", pos[0], pos[1]);
val[count] = strtol(buf, NULL, 0);

UPDATE: You can avoid using sprintf()using this snippet instead:

更新:您可以避免sprintf()使用此代码段:

char buf[5] = {"0", "x", pos[0], pos[1], 0};
val[count] = strtol(buf, NULL, 0);

回答by caf

You can either switch your compiler to C99 mode (the hhlength modifier was standardised in C99), or you can use an unsigned inttemporary variable:

您可以将编译器切换到 C99 模式(hh长度修饰符在 C99 中标准化),也可以使用unsigned int临时变量:

unsigned int byteval;
if (sscanf(pos, "%2x", &byteval) != 1)
{
    /* format error */
}
val[count] = byteval;

回答by Henri Socha

Why not do it without using sscanf, strol, etc. Below is HexToBin and as a free-bee, BinToHex. (Note originally there were returned enum error codes through an error logging system not a simple -1 return.)

为什么不使用 sscanf、strol 等来实现呢?下面是 HexToBin 和免费的 BinToHex。(注意最初通过错误记录系统返回了枚举错误代码,而不是简单的 -1 返回。)

unsigned char HexChar (char c)
{
    if ('0' <= c && c <= '9') return (unsigned char)(c - '0');
    if ('A' <= c && c <= 'F') return (unsigned char)(c - 'A' + 10);
    if ('a' <= c && c <= 'f') return (unsigned char)(c - 'a' + 10);
    return 0xFF;
}

int HexToBin (const char* s, unsigned char * buff, int length)
{
    int result;
    if (!s || !buff || length <= 0) return -1;

    for (result = 0; *s; ++result)
    {
        unsigned char msn = HexChar(*s++);
        if (msn == 0xFF) return -1;
        unsigned char lsn = HexChar(*s++);
        if (lsn == 0xFF) return -1;
        unsigned char bin = (msn << 4) + lsn;

        if (length-- <= 0) return -1;
        *buff++ = bin;
    }
    return result;
}

void BinToHex (const unsigned char * buff, int length, char * output, int outLength)
{
    char binHex[] = "0123456789ABCDEF";

    if (!output || outLength < 4) return;
    *output = '
//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] == '##代码##') || (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] != '##代码##') {
            //non-hexadecimal character encountered
            return -1;
        }
    }

    return 0;
}
'; if (!buff || length <= 0 || outLength <= 2 * length) { memcpy(output, "ERR", 4); return; } for (; length > 0; --length, outLength -= 2) { unsigned char byte = *buff++; *output++ = binHex[(byte >> 4) & 0x0F]; *output++ = binHex[byte & 0x0F]; } if (outLength-- <= 0) return; *output++ = '##代码##'; }

回答by runeks

Using mvp's suggested change, I created this function which includes error checking (invalid characters and uneven length).

使用 mvp 的建议更改,我创建了此功能,其中包括错误检查(无效字符和长度不均匀)。

This function will convert a hexadecimal string - NOT prepended with "0x" - with an even number of characters to the number of bytes specified. It will return -1 if it encounters an invalid character, or if the hex string has an odd length, and 0 on success.

此函数会将十六进制字符串 - 不以“0x”开头 - 具有偶数个字符转换为指定的字节数。如果遇到无效字符,或者十六进制字符串的长度为奇数,它将返回 -1,成功则返回 0。

##代码##