繁体   English   中英

将ASCII十六进制字符串转换为字节数组

[英]Converting ascii hex string to byte array

我有一个char数组,说char value []={'0','2','0','c','0','3'};

我想将其转换为字节数组,例如unsigned char val[]={'02','0c','03'}

这是在嵌入式应用程序中,所以我不能使用string.h函数。 我怎样才能做到这一点?

在您谈到嵌入式应用程序时,我假设您想将数字保存为值而不是字符串/字符。 因此,如果您只想将字符数据存储为数字(例如整数),则可以使用sscanf

这意味着您可以执行以下操作:

 char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
 uint8 dest_val[3];                            // We want to save 3 numbers
 for(int i = 0; i<3; i++)
 {
     sscanf(&source_val[i*2],"%x%x",&dest_val[i]); // Everytime we read two chars --> %x%x
 }
 // Now dest_val contains 0x0A, 0x03 and 0xB7

但是,如果要将其存储为字符串(如您的示例中所示),则不能使用unsigned char因为此类型的长度也只有8位,这意味着它只能存储一个字符。 在单个(无符号)字符中显示“ B3”不起作用。

编辑:根据评论可以,目标是将传递的数据保存为数值。 不幸的是,打开程序的编译器不支持sscanf ,这是最简单的方法。 无论如何,由于(我认为)这是最简单的方法,因此我将保留答案的这一部分,并尝试在此编辑中添加更多自定义方法。

关于数据类型,实际上是否有uint8都没有关系。 即使我建议使用某种整数数据类型,也可以将数据存储到unsigned char 这里的问题是,您传递的数据是一个字符/字母,您想将其解释为数值。 但是,角色的内部存储有所不同。 您可以检查ASCII表 ,在其中可以检查每个字符的内部值。 例如:

char letter = 'A'; // Internally 0x41 
char number = 0x61; // Internally 0x64 - represents the letter 'a'

如您所见,大写和小写之间也存在差异。

如果您执行以下操作:

int myVal = letter;  //

myVal 不会代表值0xA(十进制10),它将具有值0x41。

您不能使用sscanf的事实意味着您需要一个自定义函数。 因此,首先我们需要一种将一个字母转换为整数的方法:

int charToInt(char letter)
{
    int myNumerical;
    // First we want to check if its 0-9, A-F, or a-f) --> See ASCII Table
    if(letter > 47 && letter < 58)
    {
        // 0-9
        myNumerical = letter-48;
        // The Letter "0" is in the ASCII table at position 48 -> meaning if we subtract 48 we get 0 and so on...
    }
    else if(letter > 64 && letter < 71)
    {
       // A-F
       myNumerical = letter-55 
       // The Letter "A" (dec 10) is at Pos 65 --> 65-55 = 10 and so on..
    }
    else if(letter > 96 && letter < 103)
    {
       // a-f
       myNumerical = letter-87
       // The Letter "a" (dec 10) is at Pos 97--> 97-87 = 10 and so on...
    }
    else
    {
       // Not supported letter...
       myNumerical = -1;
    }
    return myNumerical;
}

现在,我们有一种方法可以将每个字符转换为数字。 另一个问题是总是将两个字符附加在一起,但这很容易:

int appendNumbers(int higherNibble, int lowerNibble)
{
     int myNumber = higherNibble << 4;
     myNumber |= lowerNibbler;
     return myNumber;
    // Example: higherNibble = 0x0A, lowerNibble = 0x03;  -> myNumber 0 0xA3
    // Of course you have to ensure that the parameters are not bigger than 0x0F 
}

现在,所有的一切都将是这样的:

 char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
 int dest_val[3];                             // We want to save 3 numbers
 int temp_low, temp_high;
 for(int i = 0; i<3; i++)
 {
     temp_high = charToInt(source_val[i*2]);
     temp_low = charToInt(source_val[i*2+1]);
     dest_val[i] = appendNumbers(temp_high , temp_low);
 }

希望我能正确理解您的问题,这对您有所帮助。

如果您有一个“适当的”数组,例如问题中声明的value ,则循环遍历它的大小以获取每个字符。 如果您使用的是使用ASCII字母(很可能是ASCII)的系统,则可以通过将数字减去'0'来将字符形式的十六进制数字转换为十进制值(请参阅链接的ASCII表以了解原因),并减去字母'A''a' (请确保没有字母比'F'高),然后加十。

当您具有第一个十六进制数字的值时,然后以相同的方式转换第二个十六进制数字。 将第一个值乘以16,然后加上第二个值。 现在,您具有一个字符形式的对应于两个十六进制数字的单字节值。


是时候看一些代码示例了:

/* Function which converts a hexadecimal digit character to its integer value */
int hex_to_val(const char ch)
{
    if (ch >= '0' && ch <= '9')
        return ch - '0';  /* Simple ASCII arithmetic */
    else if (ch >= 'a' && ch <= 'f')
        return 10 + ch - 'a';  /* Because hex-digit a is ten */
    else if (ch >= 'A' && ch <= 'F')
        return 10 + ch - 'A';  /* Because hex-digit A is ten */
    else
        return -1;  /* Not a valid hexadecimal digit */
}

...

/* Source character array */
char value []={'0','2','0','c','0','3'};

/* Destination "byte" array */
char val[3];

/* `i < sizeof(value)` works because `sizeof(char)` is always 1 */
/* `i += 2` because there is two digits per value */
/* NOTE: This loop can only handle an array of even number of entries */
for (size_t i = 0, j = 0; i < sizeof(value); i += 2, ++j)
{
    int digit1 = hex_to_val(value[i]);      /* Get value of first digit */
    int digit2 = hex_to_val(value[i + 1]);  /* Get value of second digit */

    if (digit1 == -1 || digit2 == -1)
        continue;  /* Not a valid hexadecimal digit */

    /* The first digit is multiplied with the base */
    /* Cast to the destination type */
    val[j] = (char) (digit1 * 16 + digit2);
}

for (size_t i = 0; i < 3; ++i)
    printf("Hex value %lu = %02x\n", i + 1, val[i]);

上面代码的输出是

Hex value 1 = 02
Hex value 2 = 0c
Hex value 3 = 03

关于ASCII算术的注释:字符'0'的ASCII值为48 ,字符'1'的ASCII值为49 因此, '1' - '0'将得出1

使用strtol()很容易:

#include <stdlib.h>
#include <assert.h>

void parse_bytes(unsigned char *dest, const char *src, size_t n)
{
    /** size 3 is important to make sure tmp is \0-terminated and
        the initialization guarantees that the array is filled with zeros */
    char tmp[3] = "";

    while (n--) {
        tmp[0] = *src++;
        tmp[1] = *src++;
        *dest++ = strtol(tmp, NULL, 16);
    }
}

int main(void)
{
    unsigned char d[3];
    parse_bytes(d, "0a1bca", 3);
    assert(d[0] == 0x0a);
    assert(d[1] == 0x1b);
    assert(d[2] == 0xca);
    return EXIT_SUCCESS;
}

如果不可用(即使它不是来自string.h),则可以执行以下操作:

int ctohex(char c)
{
    if (c >= '0' && c <= '9') {
        return c - '0';
    }
    switch (c) {
        case 'a':
        case 'A':
            return 0xa;

        case 'b':
        case 'B':
            return 0xb;

        /**
         * and so on
         */
    }
    return -1;
}

void parse_bytes(unsigned char *dest, const char *src, size_t n)
{
    while (n--) {
        *dest = ctohex(*src++) * 16;
        *dest++ += ctohex(*src++);
    }
}
假设8位字节(实际上不是C标准保证的,而是无处不在),则“无符号字符”的范围是0..255,而“有符号字符”的范围是-128..127。 ASCII被开发为7位代码,使用的范围是0-127,因此,两种`char'类型都可以表示相同的值。

对于现在发现的将计数的十六进制字符串从ascii转换为无符号字节的任务,这是我的看法:

unsigned int atob(char a){
    register int b;
    b = a - '0';    // subtract '0' so '0' goes to 0 .. '9' goes to 9
    if (b > 9) b = b - ('A' - '0') + 10;  // too high! try 'A'..'F'
    if (b > 15) b = b - ('a' - 'A);  // too high! try 'a'..'f'
    return b;
}

void myfunc(const char *in, int n){
    int i;
    unsigned char *ba;
    ba=malloc(n/2);
    for (i=0; i < n; i+=2){
        ba[i/2] = (atob(in[i]) << 4) | atob(in[i+1]);
    }
    // ... do something with ba
}

暂无
暂无

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

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