在 C++ 中将 csv 读取的十六进制字符串值转换为 uint8_t

Converting csv read hex string values to uint8_t in c++

所以我目前能够使用 ifstream 从 csv 文件中读取一些十六进制值。我能够读取这些值并将它们分配给一个字符串变量。但我想将它们转换为 uint8_t 值。所以基本上我想要这样的东西 uint8_t A = 0x41;

我试过 atoistoistrtol 但我似乎没有得到任何有效的输出。(我可能用错了)

int read_csv(){
using namespace std;
ifstream fin;
fin.open("simpletrajhex.txt");
while (fin.good ()){
      char[] line;
      getline (fin, line, ',');
      uint8_t hex1 = (uint8_t)stoi(line,NULL,16);
      cout << line << " " << hex1 << endl;
    }
  return 1;
}

当我阅读我的 csv 文件时,我得到了类似的东西

0xFF
0x5F
0x02
0x00
0xFF

但这些是字符串,我需要将每个值转换为 uint8_t 当我尝试转换时,什么也没有显示。

您不能存储 hex 值,因为它在 uint8_t 变量中,所以 uint8_t A = 0x41 不是可能的。相反,您将必须获得 decimal 等效于 hex数变成uint8_t.

尝试使用 std::stoul

得到十进制相当于十六进制 并从 decimal 返回 hex when你需要它。

您的代码有很多问题,但有两个主要问题与您向 uint8_t 的转换有关。尝试使用 getline (fin, line, ','); 读取 .csv 文件的一个普遍问题是您无法跟踪每一行中存在的值的数量。使用 ',' 分隔符读取将导致 getline 跳过 line-ending 并简单读取下一个值,直到遇到 EOF。最好用 getline (fin, line); 将整行读入 line,然后从 line 创建一个 stringstream,这样您就可以读取行中的值,直到到达字符串流的末尾(将值转换限制为每行内的值)。

将值存储为 uint8_t 的主要障碍是 validate 失败 stoi 转换的结果在 uint8_t 在进行分配之前。此外,由于 uint8_tunsigned 值,因此使用 stoul 更合适。虽然 C-style 转换为 (uint8_t) 是有效的,但最好使用 static_cast<uint8_t>(...)(尽管两者提供相同的结果)。最后,您尝试输出 << hex1 ... 将始终失败,因为 << 运算符需要一个 int(或 unsigned)值。

将所有这些部分放在一起,您可以修改 read_csv() 以将要打开的文件名作为参数,而不是在函数中对文件名进行硬编码(不要那样做)然后执行类似于:

int read_csv (const string& name)
{
    string line;
    ifstream fin (name);

    while (getline (fin, line)) {           /* read entire line into line */
        stringstream ss (line);             /* create stringstream from line */
        string field;                       /* string to hold each field */
        cout << "line: " << line << '\n';
        while (getline (ss, field, ',')) {  /* read each hex value from line */
            uint64_t tmp = stoul (field, 0, 0); /* convert to uint64_t */
            if (tmp <= UINT8_MAX) {         /* validate in range of uint8_t */
                uint8_t hex1 = static_cast<uint8_t>(tmp);   /* store uint8_t */
                /* output with cast to unsigned for << */
                cout << "  " << field << " -> " <<
                        static_cast<uint32_t>(hex1) << '\n';
            }
        }
    }
    return 1;
}

注意: 而不是 cout 内的大小写,你也可以在 hex1 之前加上数字 + 来强制升级,例如

cout << "  " << field << " -> " << +hex1 << '\n';

另请注意:stoul中使用0作为基数,则数字基数为auto-detected:如果前缀为0,基数为八进制,若前缀为0x0X,则基数为十六进制,否则基数是十进制。

一个使用该函数的简短示例可以是:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdint>

using namespace std;

int read_csv (const string& name)
{
    string line;
    ifstream fin (name);

    while (getline (fin, line)) {           /* read entire line into line */
        stringstream ss (line);             /* create stringstream from line */
        string field;                       /* string to hold each field */
        cout << "line: " << line << '\n';
        while (getline (ss, field, ',')) {  /* read each hex value from line */
            uint64_t tmp = stoul (field, 0, 0); /* convert to uint64_t */
            if (tmp <= UINT8_MAX) {         /* validate in range of uint8_t */
                uint8_t hex1 = static_cast<uint8_t>(tmp);   /* store uint8_t */
                /* output with cast to unsigned for << */
                cout << "  " << field << " -> " <<
                        static_cast<uint32_t>(hex1) << '\n';
            }
        }
    }
    return 1;
}

int main (int argc, char **argv) {

    if (argc < 2) {
        cerr << "error: insufficient input\n" <<
                "usage: " << argv[0] << " <file>\n";
        return 1;
    }

    read_csv (argv[1]);
}

(注意:通常鼓励 using namespace std;,因此虽然它可以简化简短示例程序的输入,但您通常希望避免包含整个 std 每个源文件中的命名空间(尤其要避免将其包含在头文件中))

示例输入文件

$ cat dat/hexcsv.csv
0xff,0x5f
0x02,0x00
0xff,0xaa

例子Use/Output

每个数值在以十进制输出之前都存储在uint8_t变量hex1中。

$ ./bin/read_csv_uint8 dat/hexcsv.csv
line: 0xff,0x5f
  0xff -> 255
  0x5f -> 95
line: 0x02,0x00
  0x02 -> 2
  0x00 -> 0
line: 0xff,0xaa
  0xff -> 255
  0xaa -> 170