I'm trying to read bytes in hex notation from a string. The bytes may or may unfortunately not be separated by whitespace, e.g. " 00 ffab c "
is a valid example and should result in 4 bytes read, 0x00, 0xff, 0xab and 0x0c. The problem is to skip whitespace but read only two adjacent digits, when present.
If the input were from a file, the task would be as easy as while(fscanf(f, "%2d", &i) == 1) ...
because sscanf
skips whitespace, the read position is tracked by the underlying FILE
, and the maximum field width is only applied to the item read, not the raw input characters containing the whitespace. But the position tracking is not possible when reading from a string; I need to use the %n
format conversion specifier which stores the number of characters read so far by this invocation into the associated variable, e.g. scanf(f, "%2d%n", &i, &readIncr)
, and manually maintain a read position by adding the respective increments.
This is somewhat cumbersome, hence I wanted to use std::istringstream
which does keep track of a position in the underlying string.
But setting a width on the input stream does not have the desired (and expected) effect; below is a minimal demonstration; for simplicity I'm using decimal integers. Documentation and examples for an input field width are scarce.
Am I doing something wrong? I this use case simply not intended?
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdio>
using namespace std;
int main()
{
const char *s = " 1234";
int i;
istringstream is(s);
if (is >> setw(2) >> i)
{
cout << "stringstream i: " << i << '\n';
}
if (sscanf(s, "%2d", &i) == 1)
{
cout << "scanf i: " << i << '\n';
}
}
The output is (with g++ and MSVC)
$ g++ -Wall -o fieldwidth fieldwidth.cpp && ./fieldwidth
stringstream i: 1234
scanf i: 12
Sadly cpp streams are far from perfect. AFAIK std::setw
works only for reading strings. What you can do is:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdio>
using namespace std;
int main()
{
const char *s = " 1234";
std::string i;
istringstream is(s);
if (is >> setw(2) >> i)
{
cout << "stringstream i: " << std::stoi(i) << '\n';
}
int j;
if (sscanf(s, "%2d", &j) == 1)
{
cout << "scanf i: " << j << '\n';
}
}
And you get expected output:
stringstream i: 12
scanf i: 12