Nastasia想问:https ://ru.stackoverflow.com/questions/1280905/Checking-for-out-of-int/1280957#1280957
我正在通过std::atoi()将string转换为int,但是string可以超出int值的范围(内部string可以大于2 147 483 647)
我想通过字符数来检查,如果超过 7 个,以便给出错误,然后逐个字符地检查字符串的最大数量。如果我执行算术运算,就会出现问题,出现越界。如何正确检查数字是否超出其值范围?
我试着这样回答:
有两因素身份验证之类的东西。在我们的例子中,从字符串中读取数字,转换为新字符串,然后进行比较。
# include <string> # include <sstream> # include <iostream> bool isBADstrtoint(std::string const & st,int & in) { int i = std::atoi(st.c_str()); std::stringstream ss; ss << i; std:: cout<<"ss.str = '"<<ss.str()<<"'"<<std::endl; if (st == ss.str()) { in = i ; return false ; } return true ; } int main(){ int i; std::string st = "12345678901"; if( isBADstrtoint(st,i)) std::cout<<"st = '"<<st <<"' is bad"<<std::endl; else std::cout<<"i = "<<i <<std::endl; }
仅适用于整数,不接受指数。
ss.str = '-539222987' st = '12345678901' is bad
使用算术运算时,您应该已经立即自己检查溢出。
int x, y , s ; s = x + y ; if ( y > 0 ) if ( s > x ) Ok else Bad else if ( y < 0 ) if ( s < x ) Ok else Bad
但我的回答被否决了。他们说,对于不能表示这种类型数字的字符串,编译器可以返回任何数字,进一步执行并不能保证使用这个返回值的程序代码的进度。
加数也是一样。如果发生溢出,编译器在比较相等==
或<
.
这是一个真实的例子,当 UB 发生时,int 类型的行为就好像它可以表示的值的范围比它实际的范围要大。–沃洛洛
#include <iostream> #include <limits> #include <type_traits> using std::cout; using std::endl; int main() { volatile int tmp = std::numeric_limits<int>::max(); int a = tmp; cout << "a+1 > a: " << ( int(a+1) > a ) << endl; cout << "a+1: " << int(a+1) << endl; cout << "a: " << a << endl; } g++ -std=c++2a -O3 -Wall -pedantic -pthread main.cpp && ./a.out a+1 > a: 1 a+1: -2147483648 a: 2147483647
如何检查字符串中的数字是否可以通过int类型正确提供?
这是一个使用检查库实现的示例:
https://godbolt.org/z/jqP7szqYf
https://godbolt.org/z/Wsb5Gsjvz
答案在很大程度上取决于“Nastasya”的含义,即“正确检查一个数字是否超出其值”。
例如,使用编译器扩展是否“正确”?如果是,那么GCC和Clang具有用于溢出的整数运算的原语。
使用特殊平台 API是否“正确” ?例如 Windows intsafe.h?
这个概念是否“正确”使用了第三方库?例如,安全数学.h
是否可以在汇编程序上“正确”编写?为检查溢出标志的目标平台自己实现加法/减法/乘法函数。
如果“正确”是指严格遵守标准,那么在标准中溢出是未定义的行为。换句话说,需要对结果和操作数进行额外检查:
像这样的东西。
更新
正如@gbg 正确指出的那样,发生溢出后,检查为时已晚,因为未定义行为的选项可能不同。例如,打开自毁系统,如阿丽亚娜 5 号火箭
因此,您需要提前检查。例如,当添加
если a > 0 то b <= (MAX_INT - a)