Reputation: 2888
I tried to use:
std::string s = "-150";
unsigned int a = atoi(s.c_str());
std::cout << a;
and
std::string s = "-150";
std::istringstream reader(s);
unsigned int a;
reader >> a;
std::cout << a;
I always get 4294967146
. I understand that it's a U_INT_MAX - 150
.
How can I get an error if number can't be converted, cause input data was invalid?
Or (at least) auto-convert to 150
.
P.S.
I want to find a way without my manipulation on string.
Upvotes: 3
Views: 11839
Reputation: 30709
It seems that even std::stoul
doesn't reject negative numbers (presumably due to the requirements of strtoul
, which it uses). Here's a test program to demonstrate:
#include <iostream> // std::cout, etc.
#include <string> // std::string, std::stoul
#include <stdexcept> // std::invalid_argument, std::out_of_range
#include <limits> // std::numeric_limits
int main(int, char **argv)
{
while (*++argv) {
std::string str(*argv);
try {
unsigned long u = std::stoul(str);
if (u > std::numeric_limits<unsigned int>::max())
throw std::out_of_range(str);
unsigned int i = u;
std::cout << "Value = " << i << std::endl;
} catch (const std::invalid_argument& e) {
std::cout << "Input could not be parsed: " << e.what() << std::endl;
} catch (const std::out_of_range& e) {
std::cout << "Input out of range: " << e.what() << std::endl;
}
}
}
Running this with arguments 150 -150 abc
gives
Value = 150
Input out of range: -150
Input could not be parsed: stoul
But, if we remove the std::numeric_limits
test, we get
Value = 150
Value = 4294967146
Input could not be parsed: stoul
Read as an unsigned long
and test the range yourself (wrap it up in a function - perhaps even a template function - if you find you need it in many places).
Upvotes: 4
Reputation: 1
How can I get an error if number can't be casted, cause input data was invalid?
You can read into a signed int
variable in 1st place:
unsigned int a = 0;
int a_input = atoi(s.c_str());
if(a_input < 0) {
std::err << "Invalid input." << std::endl;
}
else {
a = a_input;
}
If you need to cover the full range of unsigned int
input, choose the next bigger data type available:
long a_input = atol(s.c_str());
Or (at least) auto-convert to
150
.
That's not a matter of casting. You should simply use the std::abs()
function to achieve what you want:
unsigned int a = std::abs(atoi(s.c_str()));
// ^^^^^^^^
Upvotes: 2
Reputation: 2705
You expect a number as input and want to check it fits in unsigned int
, then do it so. Convert the string to an universal data type for numbers (signed, floating point, much room -> double) and check if it can be casted without precision lost to your wished type.
You want an integer with no sign, so your number has to be positive, is in given range (so far see std::numeric_limits) and has no decimal part.
Upvotes: 3