istringstream to int8_t produce unexpected result - c++

After read this FAQ, i choose to use istringstream to convert my input string to numerical value.
My code is look like this:
<template T>
T Operand<T>::getValue(const std::string &s)
{
T _value;
std::istringstream v_ss(s);
v_ss >> _value;
return _value;
}
When T is int, short, long or float, no problem i get correct value.
But when T is int8_t, this code doesn't work.
By exemple, if my input string is "10", getValue return me a int8_t with value equals 49.
With 49 == '1' in ASCII table, i guess the >> operator just read the first char in input string and stop.
Is there a trick or something i don't understand in the FAQ ?

The problem is int8_t is implemented as char.
The implementation of the input stream is working like this:
char x;
std::string inputString = "abc";
std::istringstream is(inputString);
is >> x;
std::cout << x;
The result is 'a', because for char the input stream is read char for char.
To solve the problem, provide a specialised implementation for your template method. and reading into a int, then check the bounds and convert the value into a int8_t.

Related

Input number to variable with type char in C++

In C++, how can I input a number to unsigned char variable? In C, I can accept the input using %hhu format specifier:
unsigned char var_name;
scanf("%hhu", &var_name);
//lets say I inputted 27
printf("%hhu", var_name);
//the output is 27
How can I do that in C++? The code below is my attempt to do this in C++, but it does a wrong thing. How can I write equivalent code in C++?
unsigned char var_name;
std::cin >> var_name;
//Input 27 again
std::cout << var_name;
//The output is just 2, how can I make the '7' appear?
This happens because when reading an unsigned char from std::istream, a character is read. That's just what happens, that's how std::istream works. It also makes a lot of sense, because it's quite common to want to read a single character.
The trivial solution is to use a temp variable:
unsigned char var_name;
unsigned int tmp;
std::cin >> tmp; // input 27
// optionally add checking that tmp is small enough
var_name = tmp; // truncation of unsigned ints is well defined
std::cout << var_name; // should print 27
You are only getting a 2 when printing the variable because of cin.
The maximum size of an unsigned char in C++ is usually 8 bits, which is fine for any actual character, and any digit up to 255. However this number depends on the compiler and the system. The maximum value that can be stored is in the header, as UCHAR_MAX.
Your issue here is that you are using cin, which only ever reads the first 'character' of an input if it is storing that input as a char. There are several ways around this, including taking the input as an integer and then converting to a char, or making your program work with an integer.
Hope this helps :)
When var_name is of type unsigned char, then the line
std::cin >> var_name;
is similar to
std::scanf("%c", &var_name);
i.e. C++ will assume that you want to read a single character and write the character code into var_name.
If you instead want to read a number and write that number into var_name, then you cannot use the data type char or unsigned char when using operator >>, even if the data type is technically able to represent the desired range of values. Instead, you will first have to use a variable with a larger data type, such as unsigned short, for reading the number. Afterwards, you can assign it to another variable of type unsigned char:
unsigned char var_name;
unsigned short temp;
std::cin >> temp;
if ( std::cin )
{
var_name = static_cast<unsigned char>( temp );
std::cout << var_name << '\n';
}
else
{
//TODO: handle error
}
The static_cast is not necessary, but some compilers may emit a warning due to the truncation, which will probably be suppressed by the cast. Also, using the cast makes the code more readable, because it becomes obvious that the value is being truncated.
However, I generally do not recommend that you use operator >> for user input, because it will do strange things, such as
not always read one line of input at a time, and
accept garbage such as "6sdfj23jlj" as valid input for the number 6, although the input should probably be rejected in this case.
If you want to read a number from the user with proper input validation, I recommend that you take a look at my function get_int_from_user in this answer of mine to another question.

Read uint8_t from std::stringstream as a numeric type

My understanding is that reading a uint8_t from a stringstream is a problem because the stringstream will interpret the uint8_t as a char. I would like to know how I can read a uint8_t from a stringstream as a numeric type. For instance, the following code:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
uint8_t ui;
std::stringstream ss("46");
ss >> ui;
cout << unsigned(ui);
return 0;
}
prints out 52. I would like it to print out 46.
EDIT: An alternative would to just read a string from the stringstream and then convert the solution to uint8_t, but this breaks the nice chaining properties. For example, in the actual code I have to write, I often need something like this:
void foobar(std::istream & istream){
uint8_t a,b,c;
istream >> a >> b >> c;
// TODO...
}
You can overload the input operator>> for uint8_t, such as:
std::stringstream& operator>>(std::stringstream& str, uint8_t& num) {
uint16_t temp;
str >> temp;
/* constexpr */ auto max = std::numeric_limits<uint8_t>::max();
num = std::min(temp, (uint16_t)max);
if (temp > max) str.setstate(std::ios::failbit);
return str;
}
Live demo: https://wandbox.org/permlink/cVjLXJk11Gigf5QE
To say the truth I am not sure whether such a solution is problem-free. Someone more experienced might clarify.
UPDATE
Note that this solution is not generally applicable to std::basic_istream (as well as it's instance std::istream), since there is an overloaded operator>> for unsigned char: [istream.extractors]. The behavior will then depend on how uint8_t is implemented.
Please do not use char or unsigned char(uint8_t) if you want to read in a formatted way. Your example code and its result is an expected behavior.
As we can see from https://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt2
template< class Traits >
basic_istream<char,Traits>& operator>>( basic_istream<char,Traits>& st, unsigned char& ch );
This does "Performs character input operations".
52 is an ascii code for '4'. Which means that the stringstream has read only one byte and still ready to read '6'.
So if you want work in the desired way, you should use 2-byte or bigger integer types for sstream::operator>> then cast it to uint8_t - the exact way that you self-answered.
Here's a reference for those overloads.
https://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt
After much back and forth, the answer seems to be that there is no standard way of doing this. The options are to either read off the uint8_t as either a uint16_t or std::string, and then convert those values to uint8_t:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
uint8_t ui;
uint16_t tmp;
std::stringstream ss("46");
ss >> tmp;
ui = static_cast<uint8_t>(tmp);
cout << unsigned(ui);
return 0;
}
However, such a solution disregards range checking. So you will need to implement that yourself if you need it.

Type Casting File Input to Vector Type in C++

In the main function, there are various vectors of different template types(float, int, char*). This function is called to read in formatted input from different files to fill each vector. My problem is coming from the type conversion since
v.push_back((T)(pChar));
does not like converting char* to float(presumably because of the decimal point).
Question: Is there a way to get correct conversions regardless of the data type as long as the input file is appropriate? (I've considered typeid(); but am not sold on using it)
template <class T>
void get_list(vector <T> & v, const char * path)
{
fstream file;
const char delim[1]{' '};
char line[512];
char * pChar;
file.open(path, ios_base::in);
if (file.is_open())
{
while (!file.eof())
{
file.getline(line, 512);
pChar = strtok(line, delim);
while (pChar != NULL)
{
v.push_back(pChar);
pChar = strtok(NULL, delim);
}
}
file.close();
}
else
{
cout << "An error has occurred while opening the specified file." << endl;
}
}
This is homework but this problem does not pertain directly to the objective of the assignment.
The assignment is on heaps for data structs/algorithm class.
Indeed, you can't simply cast a string to an arbitrary type, you'll need some code to parse and interpret the contents of the string. The I/O library has string streams for that:
std::stringstream ss(pChar);
T value;
ss >> value;
v.push_back(value);
This will work for all types that have a >> overload, including all built-in numeric types like float.
Alternatively, you might want to get rid of the nasty C-style tokenisation:
T value;
while (file >> value) {
v.push_back(value);
}
or
std::copy(
std::istream_iterator<T>(file),
std::istream_iterator<T>(),
std::back_inserter(v));
At the very least, change the loop to
while (file.getline(line, 512))
checking the file status after reading the line, so you don't process the final line twice.

Member Function Template to Covert a std::string to Any Numeric Type or to a std::string

Please consider the member function template. My question is embedded in comment form.
template<typename T>
GetValueResult GetValue(
const std::string &key,
T &val,
std::ios_base &(*manipulator)(std::ios_base &) = std::dec
)
{
// This member function template is intended to work for all built-in
// numeric types and std::string. However, when T = std::string, I get only
// the first word of the map element's value. How can I fix this?
// m_configMap is map<string, string>
ConfigMapIter iter = m_configMap.find(key);
if (iter == m_configMap.end())
return CONFIG_MAP_KEY_NOT_FOUND;
std::stringstream ss;
ss << iter->second;
// Convert std::string to type T. T could be std::string.
// No real converting is going on this case, but as stated above
// I get only the first word. How can I fix this?
if (ss >> manipulator >> val)
return CONFIG_MAP_SUCCESS;
else
return CONFIG_MAP_VALUE_INVALID;
}
The << and >> operators on streams are designed to work with tokens separated by whitespace. So if a string looks like "1 2" then your stringstream will only read in 1 on the first <<.
If you want multiple values I suggest you use a loop over the stream. Something like this might do...
//stringstream has a const string& constructor
std::stringstream ss(iter->second);
while (ss >> manipulator >> value) { /* do checks here /* }
With that I would suggest you look at Boost and in particular lexical_cast which might do what you want out of the box.

string input, how to tell if it is int?

I am writing a program that converts a parathensized expression into a mathematical one, and evaluates it. I've got the calculation bit written already.
I am using a stack for the operands, and a queue for the numbers. Adding operands to the stack isn't an issue, but I need to identify whether the input character is an integer, and if so, add it to the queue. Here's some code:
cout << "Enter the numbers and operands for the expression";
string aString;
do
{
cin >> aString
if (aString = int) // function to convert to read if int, convert to int
{
c_str(...);
atoi(...);
istack.push(int);
}
}
That's where I'm stuck now. I know I'm going to have to use c_str and atoi to convert it to an int. Am I taking the wrong approach?
Use the .fail() method of the stream.
If you need the string too, you can read to a string first, then attempt to convert the string to an integer using a stringstream object and check .fail() on the stringstream to see if the conversion could be done.
cin >> aString;
std::stringstream ss;
ss << aString;
int n;
ss >> n;
if (!ss.fail()) {
// int;
} else {
// not int;
}
I'll probably get flamed for this by the C++ purists.
However, sometimes the C++ library is just more work than the C library. I offer this
solution to C developers out there. And C++ developers who don't mind using some of the
features of the C library.
The whole check and conversion can be done in 1 line of C using the sscanf function.
int intval;
cin >> aString
if (sscanf(aString.c_str(), "%d", &intval)){
istack.push(intval);
}
sscanf returns the number of input arguments matched and assigned. So in this case, it's looking for one standard signed int value. If sscanf returns 1 then it succeeded in assigning the value. If it returns 0 then we don't have an int.
If you expect an integer, I would use boost::lexical_cast.
std::string some_string = "345";
int val = boost::lexical_cast<int>(some_string);
If it fails to cast to an integer, it will throw. The performance is pretty reasonable, and it keeps your code very clean.
I am unaware of any non-throwing version. You could use something like this, though I usually try to avoid letting exceptions control program flow.
bool cast_nothrow(const std::string &str, int &val) {
try {
val = boost::lexical_cast<int>(str);
return true;
} catch (boost::bad_lexical_cast &) {
return false;
}
}
Edit:
I would not recommend your integer validation checking for structure like you described. Good functions do one thing and one thing well.
Usually you'd want a more formal grammar parser to handle such things. My honest advice is to embed a scripting language or library in your project. It is non-trivial, so let someone else do the hard work.
If I actually tried to implement what you propose, I would probably do a stack based solution keeping the parenthesis levels at their own stack frame. The simplest thing would just be to hard code the simple operators (parenthesis, add, sub, etc) and assume that the rest of everything is a number.
Eventually you'd want everything broken down into some expression type. It might look something like this:
struct Expression {
virtual ~Expression() {}
virtual float value() const = 0;
};
struct Number : public Expression {
virtual float value() const {return val;}
float val;
};
struct AdditionOper : public Expression {
virtual float value() const {return lhs->value() + rhs->value();}
boost::shared_ptr<Expression> lhs;
boost::shared_ptr<Expression> rhs;
};
I'd start by parsing out the parenthesis, they will determine the order of your expressions. Then I'd split everything based on the numerical operands and start putting them in expressions. Then you're left with cases like 3 + 4 * 6 which would require some some care to get the order of operations right.
Good luck.
You can either run your function that converts a string representation of a number to a double and see if there's an error, or you can look at the contents of the string and see if it matches the pattern of a number and then do the conversion.
You might use boost::lexical_cast<double>() or std::stod() (C++11) where errors are reported with an exception, or istringstream extractors where the error is reported by setting the fail bit, or with C conversion functions that report errors by setting the global (thread local, rather) variable errno.
try {
istack.push_back(std::stod(aString));
} catch(std::invalid_argument &e) {
// aString is not a number
}
or
errno = 0;
char const *s = aString.c_str();
char *end;
double result = strtod(s,&end);
if(EINVAL==errno) {
// the string is not a number
} else {
istack.push_back(result);
}
An implementation of the second option might use a regex to see if the string matches the pattern you use for numbers, and if it does then running your conversion function. Here's an example of a pattern you might expect for floating point values:
std::regex pattern("[+-]?(\d*.\d+|\d+.?)([eE][+-]?\d+)?");
if(std::regex_match(aString,pattern)) {
istack.push_back(std::stod(aString));
} else {
// aString is not a number
}
Also, this probably doesn't matter to you, but most any built in method for converting a string to a number will be locale sensitive one way or another. One way to isolate yourself from this is to use a stringstream you create and imbue with the classic locale.
I guess the C++ (no boost) way would be this :
do
{
std::stringstream ss;
std::string test;
cin >> test;
ss << test;
int num;
if (ss >> num) // function to convert to read if int, convert to int
{
std::cout << "Number : " << num << "\n";
}
}while(true); // don't do this though..
Can you not use ctype.h http://www.cplusplus.com/reference/clibrary/cctype/. I have used this before and did not get into trouble.
Especially if you're doing base-10 input, I find the most blatant thing to do is read the string, then check that it only contains valid characters:
string s;
cin >> s;
if(strrspn(s.c_str(), "0123456789")==s.length()){
//int
} else{
//not int
}