我正在编写一个词法分析器作为编译器项目的一部分,我需要检测一个整数是否大于 int 可以容纳的整数,以便打印错误。是否有适合此目的的大整数 C++ 标准库?
9 回答
用于将数字字符串转换为整数的标准 C 库函数应该检测超出范围的数字,并将 errno 设置为 ERANGE 以指示问题。看这里
您可能可以使用 libgmp。但是,我认为出于您的目的,这只是不必要的。
例如,如果您将数字解析为 32 位无符号整数,则
- 解析第一个最多 9 个十进制数(即 floor(32*log(2)/log(10))。如果没有更多,则该数字是可以的。
- 取下一个数字。如果你得到的数字 / 10 不等于上一步的数字,那么这个数字就是坏的。
- 如果您有更多数字(例如,超过 9+1),则数字不好。
- 否则数字是好的。
请务必跳过任何前导零等。
libgmp 是一个通用的解决方案,虽然可能有点重量级。
对于轻量级的词法分析器,您可以将其视为字符串;修剪前导零,如果超过10位,则太长;如果较短则没关系,如果正好是 10 位,则字符串与最大值 2^31=2147483648 或 2^32=4294967296 进行比较。请记住,-2^31 是合法值,但 2^31 不是。还要记住八进制和十六进制常量的语法。
对于所有建议atoi的人:
- 我的 atoi() 实现没有设置 errno。
- 我的 atoi() 实现不会在溢出时返回 INT_MIN 或 INT_MAX。
- 我们不能依赖符号反转。考虑 0x4000...0。
- *2 并设置负位。
- *4 且值为 0。
- 使用以 10 为底的数字,我们的下一个数字将乘以 10。
这都是胡说八道。除非您的词法分析器正在解析数字数据,否则请停止过早的优化。它只会导致悲伤。
这种方法可能效率低下,但足以满足您的需求:
const char * p = "1234567890123";
int i = atoi( p );
ostringstream o;
o << i;
return o.str() == p;
或者,利用堆栈:
const char * p = "1234567890123";
int i = atoi( p );
char buffer [ 12 ];
snprintf( buffer, 12, "%d", i );
return strcmp(buffer,p) == 0;
这个怎么样。使用 atol,并检查溢出和下溢。
#include <iostream>
#include <string>
using namespace std;
main()
{
string str;
cin >> str;
int i = atol(str.c_str());
if (i == INT_MIN && str != "-2147483648") {
cout << "Underflow" << endl;
} else if (i == INT_MAX && str != "2147483647") {
cout << "Overflow" << endl;
} else {
cout << "In range" << endl;
}
}
如果您希望能够处理此类数字,您可能需要查看GMP 。
在您的词法分析器中,当您解析整数字符串时,您必须在添加每个新数字之前乘以 10(假设您从左到右解析)。如果该运行总计突然变为负数,则您已经超出了整数的精度。
如果您的语言(如 C)支持表达式的编译时评估,那么您可能也需要考虑这一点。
像这样的东西:
#define N 2147483643 // This is 2^31-5, i.e. close to the limit.
int toobig = N + N;
GCC 会捕捉到这一点,说“警告:表达式中的整数溢出”,但当然没有个别文字溢出。这可能超出了您的要求,只是想我会指出它是该部门真正的编译器需要的东西。
您可以分别检查该数字是高于还是低于 INT_MAX 或 INT_MIN。你需要#include <limits.h>