C++ 将十六进制字符串转换为结构
我有一个文件,里面有一大串十六进制数。以下是前几行:C++ 将十六进制字符串转换为结构,c++,string,struct,casting,solaris,C++,String,Struct,Casting,Solaris,我有一个文件,里面有一大串十六进制数。以下是前几行: 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; 我要
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;
我要做的是读取上面的字符串并将其存储在struct中。我可以假设输入是有效的(在我得到它之前已经验证过)
我已经有了一个循环,可以读取文件并将整个项放入字符串中:
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...?
如果你关心效率的话,不要把整件事读成一个字符串,然后再转换。只需一次读一个单词,然后将其转换。您的循环应该类似于:
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");
校准c;
uint32\u t*dest=重新解释铸件(&c);
while(true){
char-hexText[8];
//TODO:尝试从文件中读取8个字节,然后跳过空白
//TODO:在EOF上中断循环
std::uint32\u t hexValue=0;//TODO:将十六进制转换为dword
//假定结构padding&packing与转储版本的匹配
//假设结构大小正好是32字节的倍数(带填充)
静态(sizeof(校准)%4==0);
断言(dest-&c
将8个字符的十六进制转换为实际的4字节整数是一个很好的练习,其他地方也做了很好的介绍,所以我省略了它(以及文件读取,同样也做了很好的介绍)
注意循环中的两个假设:第一个假设不能在运行时或编译时检查,必须事先商定,或者必须做额外的工作来正确序列化结构(处理结构打包和填充等)。最后一个参数至少可以在编译时用static\u assert
检查
此外,在转换十六进制字符串时,必须注意确保文件中十六进制字节的endianness与执行程序的架构的endianness相匹配。这将取决于十六进制是否首先以特定的结束形式写入(在这种情况下,您可以很容易地将其从已知结束形式转换为当前体系结构的结束形式),或者它是否依赖于体系结构(在这种情况下,您别无选择,只能假设结束形式与当前体系结构相同)
如何从长整数到校准
卡梅隆的回答很好,可能是你想要的
我在这里提供了另一种方法(也许没有那么不同)
注1:您的文件输入需要重新工作。我建议 a) 使用getline()一次提取一行到字符串中 b) 将一个条目转换为uint32_t(我将使用stringstream而不是atol) 一旦您学会如何检测和恢复无效输入, 然后,您可以将a)和b)组合为一个步骤 c) 然后在您的结构中安装uint32\t,我的 下面的内容可能会提供一些见解
注2:我在比特领域工作多年,对它们产生了厌恶。 我从未发现它们比其他选择更方便 我更喜欢的替代方案是位掩码和场移位 从您的问题陈述中我们可以看出,您的问题似乎不需要位字段(Cameron的回答说明了这一点)
注3:并非所有编译器都会为您打包这些位字段 我使用的最后一个编译器需要所谓的“pragma” ubuntu上的G++4.8似乎可以很好地打包字节(即不需要pragma) 原始代码的sizeof(校准)是4。。。i、 e.打包 另一个问题是,当您更改选项、升级编译器或更改编译器时,打包可能会意外更改 我的团队的工作是在CTOR中始终有一个针对结构大小的断言和几个字节偏移量
注4:我没有说明如何使用“union”在校准结构上对齐uint32_t阵列 这可能比重新解释cast方法更可取。检查你的要求,组长,教授
无论如何,在您最初努力的精神下,考虑以下结构结构的补充:
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;
这段代码的目的是帮助您查看位字段如何映射到数据的lsbyte到msbyte。如何访问静态断言?此外,我使用的是恐龙时代的旧编译器,因此我似乎也无法访问uint32。@user:
static\u assert
是C++11中引入的语言级关键字。Boost有一个版本,只使用在旧编译器中工作的模板。否则,您可以在运行时断言uint32\u t
位于cstdint
标题中——如果编译器的标准库没有,您只需typedef
自己将其设置为unsigned int
(当然,这取决于平台上unsigned int
的大小)。你应该考虑升级你的编译器,当然这可能会改变结构布局:-我在一个不相信新技术的公司工作。我对我们的工具抱怨了很多次。我最终找到了解决问题的办法。我只是将字符串转换为二进制,然后使用substr()提取位。可能是最丑陋的解决方案,但它确实有效,而且速度并不像我担心的那么慢。
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