将两个ASCII十六进制字符(两个ASCII字节)转换为一个字节

3
我想将两个ASCII字节转换为一个十六进制字节。 例如:0x30 0x43 => 0x0C , 0x34 0x46 => 0x4F ...
ASCII字节是介于0x300x39之间的数字或介于AF之间的字母(仅大写),因此介于0x410x46之间。
我知道如何使用数字0x340x46“构建”0x4F0x4F = 0x34 * 0x10 + 0x46 因此,实际上,我想将一个ASCII字节转换为十六进制值。
为此,我可以构建一个数组来将十六进制值分配给ASCII字符:
0x30 => 0x00
0x31 => 0x01
...
0x46 => 0x0F

但是,也许有一个最“适当”的解决方案。

该程序将在AVR微控制器上运行,并使用avr-gcc编译,因此scanf() / printf()解决方案不适用。

你有什么想法吗? 谢谢


6
ASCII字节或十六进制字节并不存在。 - David Heffernan
2
你(显然!)想要做的是通过将两个字节解释为ASCII符号,这些符号表示十六进制数字,并发出相应的十六进制值,从而将一对字节转换为单个字节。解决这类问题需要精确理解您正在做什么;精确的沟通也会有很大帮助 :) 您必须确保自己从根本上理解数据是什么。就像David所说,字节只是字节;没有ASCII字节或十六进制字节。 - Karl Knechtel
ASCII 字节 = 表示 ASCII 字符的字节,十六进制字节 = 以十六进制表示的字节。我知道字节只是字节;我只是不知道如何解释。但是其他人已经理解我的意思了。最重要的不是吗? - Loïc G.
6个回答

11

我无法理解你的示例,但如果您想将包含十六进制ASCII字符的字符串转换为其字节值(例如,使字符串“56”成为字节0x56),则可以使用以下方法(假设您的系统正在使用ASCII)

uint8_t*
hex_decode(const char *in, size_t len,uint8_t *out)
{
        unsigned int i, t, hn, ln;

        for (t = 0,i = 0; i < len; i+=2,++t) {

                hn = in[i] > '9' ? in[i] - 'A' + 10 : in[i] - '0';
                ln = in[i+1] > '9' ? in[i+1] - 'A' + 10 : in[i+1] - '0';

                out[t] = (hn << 4 ) | ln;
        }

        return out;
}

您可以像这样使用它,例如:

char x[]="1234";
uint8_t res[2];
hex_decode(x,strlen(x),res);

现在,res(其长度至少为in参数的一半)包含了2个字节0x12、0x34。

还要注意的是,此代码需要十六进制字母A-F为大写,a-f无效(并且它不进行任何错误检查 - 因此您必须传递有效的内容)。


1
使用(in[i]|32)-'a'+10,现在您可以支持大写和小写字母(只需要再添加一条机器码指令)。 - R.. GitHub STOP HELPING ICE
uint8_t 不是一个字节吗?如果它应该包含两个字节,那不应该是 uint16_t 吗? - Rudy Velthuis
@Rudy Velthuis 这应该是一个字节,因为它只包含1个字节,而不是2个。 - nos
@nos:是的,我看到它是一个uint8_t数组。脑抽了,抱歉。 - Rudy Velthuis
请确保包含cytpe.h头文件。 - ojblass

10
您可以使用strtol(),它是avr-libc的一部分,或者您可以很容易地编写适合您特定情况的代码:
unsigned char charToHexDigit(char c)
{
  if (c >= 'A')
    return c - 'A' + 10;
  else
    return c - '0';
}

unsigned char stringToByte(char c[2])
{
  return charToHexDigit(c[0]) * 16 + charToHexDigit(c[1]);
}

1
好的,这很容易... 我想到了对0到9之间的数字进行4位左移,但解决方案甚至更简单!谢谢 - Loïc G.
这是一个笑话吗?: $ man ascii 没有ascii的手册条目。 - Loïc G.
@Loic:不,你可能错过了手册页面。这是英文版本:http://linux.die.net/man/7/ascii - Adam Rosenfield
stringToByte函数返回的值是否被强制转换为unsigned char,是因为该函数被声明为这样吗? - Tom Russell
是的。整数提升使得stringToByte内部的所有算术运算都在int类型上进行,然后将结果作为unsigned char返回。 - Carl Norum

0

它能工作,但可以进行更多的优化!

inline uint8_t  twoAsciiByteToByte(const std::string& s)
{
    uint8_t r = 0;

    if (s.length() == 4)
    {
        uint8_t a = asciiToByte(s[0]);
        uint8_t b = asciiToByte(s[1]);
        uint8_t c = asciiToByte(s[2]);
        uint8_t d = asciiToByte(s[3]);

        int h = (a * 10 + b);
        int l = (c * 10 + d);

        if (s[0] == '3')
            h -= 30;
        else if (s[0] == '4')
            h -= 31;

        if (s[2] == '3')
            l -= 30;
        else if (s[2] == '4')
            l -= 31;

        r = (h << 4) | l;
    }

    return r;
}

内联函数 uint8_t asciiToByte(char c) {如果 (c >= '0' && c <= '9') 返回 c - '0';如果 (c >= 'A' && c <= 'F') 返回 c - 'A' + 10;返回 0; } - Dmitry

0

这里有一个适用于大小写十六进制字符串的版本:

void hex_decode(const char *in, size_t len, uint8_t *out)
{
  unsigned int i, hn, ln;
  char hc, lc;

  memset(out, 0, len);

  for (i = 0; i < 2*len; i += 2) {

    hc = in[i];
    if ('a' <= hc && hc <= 'f') hc = toupper(hc);
    lc = in[i+1];
    if ('a' <= lc && lc <= 'f') lc = toupper(lc);

    hn = hc > '9' ? hc - 'A' + 10 : hc - '0';
    ln = lc > '9' ? lc - 'A' + 10 : lc - '0';

    out[i >> 1] = (hn << 4 ) | ln;
  }
}

0
任务:
将包含十六进制ASCII字符的字符串转换为其字节值,因此ASCII "FF" 变为 0xFF,而ASCII "10" (x31x30x00) 变为 0x10
char asciiString[]="aaAA12fF";// input ascii hex string 
char result[4];               // byte equivalent of the asciiString (the size should be at half of asciiString[])

// 最终结果应该是:

result[0] = 0xAA;
result[1] = 0xAA;       
result[2] = 0x12;
result[3] = 0xFF;

//1. 第一步:将asciiString转换为仅包含大写字母的字符串:

// convert string to upper cases:
stringToUpperCases(asciiString);

使用:

void stringToUpperCases(char *p)
{   
    for(int i=0; *(p+i) !='\0'; i++)
    {
        *(p+i) = (unsigned char) toupper( *(p+i) );
    }
}

//2. 将包含十六进制 ASCII 字符的字符串转换为其字节值:

// convert string to bytes:

int nrOfBytes = stringToBytes(asciiString,result);

//use:  
unsigned char charToHexDigit(char c)
{
if (c >= 'A')
    return (c - 'A' + 10);
else
    return (c - '0');
}

unsigned char ascii2HexToByte(char *ptr)
{
    return charToHexDigit( *ptr )*16 + charToHexDigit( *(ptr+1) );
}

int stringToBytes(char *string, char *result)
{
    int k=0;
    int strLen = strlen(string);

    for(int i = 0; i < strLen; i = i + 2)
    {
        result[k] = ascii2HexToByte( &string[i] );
        k++;
    }

    return k; // number of bytes in the result array 
}   

//3. 输出结果:

printNrOfBytes(nrOfBytes, result);

// 使用:

void printNrOfBytes(int nr, char *p)
{
   for(int i= 0; i < nr; i++)
    {
        printf( "0x%02X ", (unsigned char)*(p+i) );
    }
    printf( "\n");
}

//4. 结果应该是:

0xAA 0xAA 0x12 0xFF

//5. 这是测试程序:

char asciiString[]="aaAA12fF"; // input ascii hex string 
char result[4];                // result  
// convert string to upper cases:
stringToUpperCases(asciiString);

// convert string to bytes
int nrOfBytes = stringToBytes(asciiString,result);

// print result:
printNrOfBytes(nrOfBytes, result);

// result:
//  0xAA 0xAA 0x12 0xFF

0

将2个十六进制字符转换为一个字节需要分两步完成:

  1. char ab转换为它们的数字形式(例如,'F' -> 0xF),这可以通过两个大的if else分支来完成,检查字符是否在范围'0''9''A''F''a''f'之间。

  2. 第二步是通过将a(最大值为0xF0b0000_FFFF))向左移动4位(a << 4 -> 0b1111_0000),然后对ab应用按位或操作((a << 4) | b)将两个数字连接起来:

a: 0000_1111
b: 1111_0000
-> 1111_1111

#include <stdio.h>
#include <stdint.h>

#define u8 uint8_t
#define u32 uint32_t

u8 to_hex_digit(char a, char b) {
    u8 result = 0;

    if (a >= 0x30 && a <= 0x39) {
        result = (a - 0x30) << 4;
    } else if (a >= 0x41 && a <= 0x46) {
        result = (a - 0x41 + 10) << 4;
    } else if (a >= 0x61 && a <= 0x7A) {
        result = (a - 0x61 + 10) << 4;
    } else {
        printf("invalid hex digit: '%c'\n", a);
    }

    if (b >= 0x30 && b <= 0x39) {
        result |= b - 0x30;
    } else if (b >= 0x41 && b <= 0x46) {
        result |= b - 0x41 + 10;
    } else if (b >= 0x61 && b <= 0x7A) {
        result |= b - 0x61 + 10;
    } else {
        printf("invalid hex digit: '%c'\n", b);
    }

    return result;
}

u32 main() {
    u8 result = to_hex_digit('F', 'F');
    printf("0x%X (%d)\n", result, result);

    return 0;
}

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