将 HEX char 数组存储在字节数组中,而不更改为 ASCII 或任何其他内容

Store HEX char array in byte array with out changing to ASCII or any thing else

我的 char 数组是 "00000f01" 我希望它像 byte out[4]={0x00,0x00,0x0f,0x01}; 我尝试了@ChrisA 发送的代码,感谢他 Serial.println( b,HEX ); 显示准确我需要什么,但第一个我无法访问这个输出数组,因为当我尝试打印 "out" 数组时它看起来是空的我也试过这个代码:

void setup() {
    Serial.begin(9600);
    char arr[] = "00000f01";
    byte out[4];
    byte arer[4];
    auto getNum = [](char c){ return c ; };
    byte *ptr = out;
    for(char *idx = arr ; *idx ; ++idx, ++ptr ){
        *ptr = (getNum( *idx++ ) << 4) + getNum( *idx );
    }
    int co=0;
    //Check converted byte values.
    for( byte b : out ){
        Serial.println( co );
        Serial.println( b,HEX ); 
        arer[co]=b;
        co++; 
    }
    //    Serial.print(getNum,HEX); 
    //    Serial.print(out[4],HEX); 
    //    Serial.print(arer[4],HEX); 
    /*
    none of this codes commented above worked*/
}

void loop() {
}   

但它也不起作用。请帮助我。

我不确定您所说的“...不更改为 ASCII 或任何其他内容”是什么意思,所以我可能误解了您的问题。

无论如何,下面是一些将十六进制字符串转换为无符号数组的简单代码。

unsigned getVal(char c)
{
  assert(
      (c >= '0' && c <= '9') ||
      (c >= 'a' && c <= 'f') ||
      (c >= 'A' && c <= 'F'));

  if (c - '0' < 10) return c - '0';
  if (c - 'A' < 6) return 10 + c - 'A';
  return 10 + c - 'a';
}

int main()
{
  char arr[] = "c02B0f01";
  unsigned out[4];
  for (auto i = 0; i < 4; ++i)
  {
    out[i] = 16*getVal(arr[2*i]) + getVal(arr[2*i+1]);
  }

  for (auto o : out)
  {
    std::cout << o << std::endl;
  }
}

输出:

192
43
15
1

如果将打印更改为

  for (auto o : out)
  {
    std::cout << "0x" << std::hex << o << std::dec << std::endl;
  }

输出将是:

0xc0
0x2b
0xf
0x1

你的问题标题让我相信你对 char 数组的理解或你提出问题的方式中缺少某些东西。人们通常难以理解十六进制 字符 或数字与内存中字节表示之间的区别。快速解释:

在内部,所有内存都是二进制的。您可以选择以位、ASCII、十进制或十六进制来表示(即显示)它,但它不会改变存储在内存中的内容。另一方面,由于内存只是二进制的,字符总是需要字符编码。这可以是 unicode 或其他更奇特的编码,但通常它只是 ASCII。所以如果你想要一串字符,无论是拼出十六进制数还是句子还是随机字母,都必须用ASCII编码。

现在body的问题很容易解决了:

AFAIK,没有办法 "capture" Serial.println( b,HEX ) 的输出实用,所以你需要找到另一种方法来从十六进制字符进行转换。 getNum() lambda 提供了绝佳的机会。目前它什么都不做,但如果你调整它,字符 '0' 变成数字 0,字符 'f' 变成数字 15,并且依此类推,一切顺利。

这是一种快速而肮脏的方法:

void setup() {
    Serial.begin(9600);
    char arr[] = "00000f01";
    byte out[4];
    byte arer[4];
    auto getNum = [](char c){ return (c <= '9' ? c-'0' : c-'a'+10) ; };
    byte *ptr = out;
    for(char *idx = arr ; *idx ; ++idx, ++ptr ){
        *ptr = (getNum( *idx++ ) << 4) + getNum( *idx );
    }
    int co=0;
    //Check converted byte values.
    for( byte b : out ){
        Serial.println( co );
        if(b < 0x10)
          Serial.print('0');
        Serial.println( b,HEX ); 
        arer[co]=b;
        co++; 
    }
}

void loop() {
}

我所做的就是修改 getNum,因此 returns 0 用于 '0'15 用于 'f',并且等等。它通过从字符 '0''9' 中减去字符 '0' 的值,或者从字符 'a' 中减去字符 'a' 的值来实现通过 'f'。幸运的是,字符 '0''9' 的值一次增加一个,从 'a''f' 的字符也是如此。请注意,如果您输入 'F' 或其他内容,这将失败,但它会为您显示的示例做。

当我在 Uno 上 运行 上面的代码时,我得到这个输出:

0
00
1
00
2
0F
3
01

这似乎是你想要的。

结语

为了演示 C++ 中的 print 函数如何让您在打印的实际值方面误入歧途,请考虑 cout 版本:

如果我在 C++14 中编译并运行以下代码:

#include <iostream>
#include <iomanip>
#include <string>

typedef unsigned char byte;

int main()
{
    char arr[] = "00000f01";
    byte out[4];
    byte arer[4];
    auto getNum = [](char c){ return c ; };
    byte *ptr = out;
    for(char *idx = arr ; *idx ; ++idx, ++ptr ){
        *ptr = (getNum( *idx++ ) << 4) + getNum( *idx );
    }
    int co=0;
    //Check converted byte values.
    for( byte b : out ){
        std::cout << std::setfill('0') << std::setw(2) << std::hex << b;
        arer[co]=b;
        co++;
    }
}

我得到这个输出:

00000f01 

似乎表明已发生从十六进制字符的转换。但这只是因为 cout 忽略 std::hex 并将 b 视为要以 ASCII 打印的字符。因为字符串 "00000f01"'0' 作为每对中的第一个字符,它恰好有一个十六进制值 (0x30),低 nybble 值为零,所以 (getNum( *idx++ ) << 4) 恰好什么都不做。所以 b 将包含每对中的原始第二个字符,当以 ASCII 打印时,它看起来像一个十六进制字符串。