将十六进制字符串转换为结构
Converting hex String to structure
我有一个文件,其中包含一个十六进制的大字符串。以下是前几行:
0000038f
0000111d
0000111d
03030303
//Goes on for a long time
我有一个大的结构,旨在保存这些数据:
typedef struct
{
unsigned int field1: 5;
unsigned int field2: 11;
unsigned int field3: 16;
//Goes on for a long time
}calibration;
我想做的是读取上面的字符串并将其存储在结构中。我可以假设输入是有效的(在我得到它之前已经过验证)。
我已经有了一个循环,它读取文件并将整个项目放在一个字符串中:
std::string line = "";
std::string hexText = "";
while(!std::getline(readFile, line))
{
hexText += line;
}
//Convert string into calibration
//Convert string into long int
long int hexInt = strtol(hexText.c_str(), NULL, 16);
//Here I get stuck: How to get from long int to calibration...?
如何从长int到校准。。。?
卡梅伦的回答很好,可能也是你想要的。
我在这里提供了另一种(也许没有那么不同)方法。
注1:您的文件输入需要重新处理。我会建议
a) 使用getline()一次将一行提取到字符串中
b) 将一个条目转换为uint32_t(我会使用字符串流而不是atol)
一旦您学会了如何检测无效输入并从中恢复,然后你可以把a)和b)组合成一个步骤
c) 然后在您的结构中安装uint32_t下面提供的内容可能会提供真知灼见。
注2:我在钻头领域工作多年,对钻头产生了反感。我从未发现它们比其他选择更方便。
我更喜欢的替代方案是比特掩码和场偏移。
就我们从你的问题陈述中可以看出,你的问题似乎不需要位域(Cameron的回答说明了这一点)。
注3:并非所有编译器都会为您打包这些位字段。
我使用的最后一个编译器需要所谓的"pragma"。
ubuntu上的G++4.8似乎可以很好地封装字节(即不需要pragma)
原始代码的(校准)大小为4。。。即打包。
另一个问题是,当您更改选项或升级编译器或更改编译器时,打包可能会意外更改。
我的团队的工作是始终在CTOR中对结构大小和几个字节偏移量进行断言。
注4:我没有说明使用"union"在校准结构上对齐uint32_t数组。
这可能比重新解释演员阵容的方法更可取。检查你的要求,团队负责人,教授。
无论如何,本着您最初努力的精神,考虑在结构校准中添加以下内容:
typedef struct
{
uint32_t field1 : 5;
uint32_t field2 : 11;
uint32_t field3 : 16;
//Goes on for a long time
// I made up these next 2 fields for illustration
uint32_t field4 : 8;
uint32_t field5 : 24;
// ... add more fields here
// something typically done by ctor or used by ctor
void clear() { field1 = 0; field2 = 0; field3 = 0; field4 = 0; field5 = 0; }
void show123(const char* lbl=0) {
if(0 == lbl) lbl = " ";
std::cout << std::setw(16) << lbl;
std::cout << " " << std::setw(5) << std::hex << field3 << std::dec
<< " " << std::setw(5) << std::hex << field2 << std::dec
<< " " << std::setw(5) << std::hex << field1 << std::dec
<< " 0x" << std::hex << std::setfill('0') << std::setw(8)
<< *(reinterpret_cast<uint32_t*>(this))
<< " => " << std::dec << std::setfill(' ')
<< *(reinterpret_cast<uint32_t*>(this))
<< std::endl;
} // show
// I did not create show456() ...
// 1st uint32_t: set new val, return previous
uint32_t set123(uint32_t nxtVal) {
uint32_t* myVal = reinterpret_cast<uint32_t*>(this);
uint32_t prevVal = myVal[0];
myVal[0] = nxtVal;
return (prevVal);
}
// return current value of the combined field1, field2 field3
uint32_t get123(void) {
uint32_t* myVal = reinterpret_cast<uint32_t*>(this);
return (myVal[0]);
}
// 2nd uint32_t: set new val, return previous
uint32_t set45(uint32_t nxtVal) {
uint32_t* myVal = reinterpret_cast<uint32_t*>(this);
uint32_t prevVal = myVal[1];
myVal[1] = nxtVal;
return (prevVal);
}
// return current value of the combined field4, field5
uint32_t get45(void) {
uint32_t* myVal = reinterpret_cast<uint32_t*>(this);
return (myVal[1]);
}
// guess that next 4 fields fill 32 bits
uint32_t get6789(void) {
uint32_t* myVal = reinterpret_cast<uint32_t*>(this);
return (myVal[2]);
}
// ... tedious expansion
} calibration;
以下是一些测试代码来说明其用途:
uint32_t t125()
{
const char* lbl =
"n 16 bits 11 bits 5 bits hex => dec";
calibration cal;
cal.clear();
std::cout << lbl << std::endl;
cal.show123();
cal.field1 = 1;
cal.show123("field1 = 1");
cal.clear();
cal.field1 = 31;
cal.show123("field1 = 31");
cal.clear();
cal.field2 = 1;
cal.show123("field2 = 1");
cal.clear();
cal.field2 = (2047 & 0x07ff);
cal.show123("field2 = 2047");
cal.clear();
cal.field3 = 1;
cal.show123("field3 = 1");
cal.clear();
cal.field3 = (65535 & 0x0ffff);
cal.show123("field3 = 65535");
cal.set123 (0xABCD6E17);
cal.show123 ("set123(0x...)");
cal.set123 (0xffffffff);
cal.show123 ("set123(0x...)");
cal.set123 (0x0);
cal.show123 ("set123(0x...)");
std::cout << "n";
cal.clear();
std::cout << "get123(): " << cal.get123() << std::endl;
std::cout << " get45(): " << cal.get45() << std::endl;
// values from your file:
cal.set123 (0x0000038f);
cal.set45 (0x0000111d);
std::cout << "get123(): " << "0x" << std::hex << std::setfill('0')
<< std::setw(8) << cal.get123() << std::endl;
std::cout << " get45(): " << "0x" << std::hex << std::setfill('0')
<< std::setw(8) << cal.get45() << std::endl;
// cal.set6789 (0x03030303);
// std::cout << "get6789(): " << cal.get6789() << std::endl;
// ...
return(0);
}
以及测试代码输出:
16 bits 11 bits 5 bits hex => dec
0 0 0 0x00000000 => 0
field1 = 1 0 0 1 0x00000001 => 1
field1 = 31 0 0 1f 0x0000001f => 31
field2 = 1 0 1 0 0x00000020 => 32
field2 = 2047 0 7ff 0 0x0000ffe0 => 65,504
field3 = 1 1 0 0 0x00010000 => 65,536
field3 = 65535 ffff 0 0 0xffff0000 => 4,294,901,760
set123(0x...) abcd 370 17 0xabcd6e17 => 2,882,366,999
set123(0x...) ffff 7ff 1f 0xffffffff => 4,294,967,295
set123(0x...) 0 0 0 0x00000000 => 0
get123(): 0
get45(): 0
get123(): 0x0000038f
get45(): 0x0000111d
此代码的目标是帮助您了解位字段如何映射到数据的lsbyte到msbyte。
如果你关心效率,不要把整件事读成字符串然后转换。只需一次读一个单词,然后转换。你的循环应该看起来像:
calibration c;
uint32_t* dest = reinterpret_cast<uint32_t*>(&c);
while (true) {
char hexText[8];
// TODO: Attempt to read 8 bytes from file and then skip whitespace
// TODO: Break out of the loop on EOF
std::uint32_t hexValue = 0; // TODO: Convert hex to dword
// Assumes the structure padding & packing matches the dump version's
// Assumes the structure size is exactly a multiple of 32-bytes (w/ padding)
static_assert(sizeof(calibration) % 4 == 0);
assert(dest - &c < sizeof(calibration) && "Too much data");
*dest++ = hexValue;
}
assert(dest - &c == sizeof(calibration) && "Too little data");
将8个字符的十六进制转换为实际的4字节int是一个很好的练习,在其他地方也有很好的介绍,所以我省略了它(以及文件读取,也有同样的介绍)。
注意循环中的两个假设:第一个不能在运行时或编译时检查,必须事先达成一致,否则必须做额外的工作来正确序列化结构(处理结构打包和填充等)。最后一个至少可以在编译时用static_assert
检查。
此外,在转换十六进制字符串时,必须注意确保文件中十六进制字节的端序与执行程序的体系结构的端序相匹配。这将取决于十六进制最初是以特定的endianness编写的(在这种情况下,您可以很容易地将其从已知endianness转换为当前体系结构的endianness),还是取决于它是否依赖于体系结构(在这种情况下,您别无选择,只能假设endianness与当前体系结构相同)。
- 在C++中将结构转换和存储为二进制
- 如何大致将 cpp 代码结构转换为 python
- 如何将可变大小的结构转换为字符数组
- 尝试传递结构数组,但出现"无法将'结构'转换为'结构*'错误
- 我可以安全地将浮点数的结构转换为浮点数组吗C++?
- 如何将结构转换为字符串?
- 如何将C++结构转换为 C# 等效结构?
- 将结构转换为布尔值
- 将具有不同字段的结构转换为 uint8 的数组
- 将 constexpr 结构转换为运行时结构
- 将结构转换为类
- 我必须将记录结构转换为一类,并且不断遇到多个错误
- 如何将 ANSI C 结构转换为 C++ 类,但保持其 ANSI C 友好
- 将 C++ 中的结构转换为 Java 中的类
- 将结构转换为 constexpr 数组uint8_t
- 将大型结构转换为小型C
- c++正在将未知结构转换为字符串
- C++隐式将平凡可构造的结构转换为成员
- 将C++联合结构转换为 VB6
- C到C++:将结构转换为类