So I am currently able to read some hex values from a csv file using ifstream. I am able to read the values and assign them to a string variable. But I want to convert them to uint8_t
values. So essentially I want something like this uint8_t A = 0x41;
I have tried atoi
, stoi
, and strtol
but i don't seem to get any valid output.(I might be using them wrong)
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;
}
When I read my csv file i get something similar
0xFF
0x5F
0x02
0x00
0xFF
But these are strings and I need each value to be converted to uint8_t
and when I try convert nothing shows up.
You have a number of problems with your code, but two primary problems related to your conversion to uint8_t
. A general problem with attempting to read a .csv
file with getline (fin, line, ',');
is you have no way of tracking the number of values present in each line. Reading with the ','
delimiter will cause getline
to skip the line-ending and simple read the next value until EOF
is encountered. Better to read an entire line into line
with getline (fin, line);
and then create a stringstream
from line
allowing you to read the value in the line until the end of the stringstream is reached (limiting the value conversions to those within each line).
The primary obstacle to storing the values as uint8_t
is your failure the validate the the result of the stoi
conversion is within the range of uint8_t
before making the assignment. Further, since uint8_t
is an unsigned
value, use of stoul
is more appropriate. While the C-style cast to (uint8_t)
is valid, it is better to use a static_cast<uint8_t>(...)
(though both provide the same result). Finally, your attempt to output << hex1 ...
will always fail as the <<
operator expects an int
(or unsigned
) value.
Putting all of those pieces together, you can rework your read_csv()
to take the name of the file to open as a parameter rather than hardcoding the filename in the function (don't do that) and do something like:
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;
}
note: rather than casing within cout
you can also precede hex1
with a numeric +
to force the promotion, e.g.
cout << " " << field << " -> " << +hex1 << '\n';
also note: that using 0
for the base in stoul
, the numeric base is auto-detected: if the prefix is 0, the base is octal, if the prefix is 0x or 0X, the base is hexadecimal, otherwise the base is decimal.
A short example making use of the function could be:
#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]);
}
(note: using namespace std;
is generally encouraged, so while it can ease typing for short example programs, you will generally want to avoid including the entire std
namespace in each source file (and especially avoid including it in header files))
Example Input File
$ cat dat/hexcsv.csv
0xff,0x5f
0x02,0x00
0xff,0xaa
Example Use/Output
Each of the numeric values are store in the uint8_t
variable hex1
before being output in decimal.
$ ./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