将 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 打印时,它看起来像一个十六进制字符串。
我的 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 打印时,它看起来像一个十六进制字符串。