C 如何处理整数溢出?
我正在尝试处理整数溢出。我的代码是:C 如何处理整数溢出?,c,int,overflow,C,Int,Overflow,我正在尝试处理整数溢出。我的代码是: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<limits.h> int isInt (char *s) { char *ep = NULL; long i = strtol (s, &ep, 10); if ((*ep == 0) || (!strcmp(ep,"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<limits.h>
int isInt (char *s)
{
char *ep = NULL;
long i = strtol (s, &ep, 10);
if ((*ep == 0) || (!strcmp(ep,"\n")))
return 1; // it's an int
return 0;
}
int main()
{
char *buffer = NULL;
size_t count = 0;
ssize_t ret;
//AMINO *a_acid;
int num;
for(;;)
{
printf("Please enter an integer:");
if((ret = getline(&buffer, &count, stdin)) < 0)
{
perror("getline: error\n");
free(buffer);
exit(EXIT_FAILURE);
}
if(!isInt(buffer))
{
perror("you are not entering int , Try again:");
continue;
}
sscanf(buffer, "%d",&num);
printf("%d\n", num);
if ((num > INT_MAX)|| (num < 0))
{
perror("you overflowed int variable , Try again:\n ");
continue;
}
break;
}
}
*为什么它适用于这个号码338479759475637465765。但它不适用于58678946895785。我在程序中使用的逻辑是,当它超出界限时,int变量给出一些-1或负值。我读了很多文章,但还是不太清楚 你把你的类型搞混了 在
isInt
函数中,使用strtol
,返回long
来检查值。然后在main
函数中,将sscanf
与%d
一起使用,该函数读入int
在您的系统上,long
似乎是64位,而int
是32位。因此,strtol
无法完全转换338479759475637465765,因为它大于64位变量所能容纳的值。然后尝试转换58678946895785,将适合64位变量,但不适合32位变量
您应该将sscanf
读入long
。然后您可以将该值与INT\u MAX
进行比较:
long num;
...
sscanf(buffer, "%ld", &num);
printf("%ld\n", num);
if ((num > INT_MAX)|| (num < INT_MIN))
{
printf("you overflowed int variable , Try again:\n ");
continue;
}
long num;
...
sscanf(缓冲区、%ld、&num);
printf(“%ld\n”,num);
如果((num>INT_MAX)| |(num
还要注意,在这里调用peror
没有意义。只有在调用设置sscanf(缓冲区、任何不带宽度的\u格式和任何类型)的函数后才能使用它代码>不足以检测溢出
如果转换的结果无法在对象中表示,则行为未定义。C11dr§7.21.6.2 10
不要使用*scanf()
系列来检测溢出。它可能在某些情况下起作用,但在一般情况下不起作用
而是使用
strto**()
函数。然而,即使是OP的isInt()
也是错误编码的,因为它错误地评估了isInt(“\n”)
,isInt(“”
,isInt(“),999..各种大值…999”)
和int
一样好
备选方案:
bool isint_alt(const char *s) {
char *endptr;
errno = 0;
long y = strtol(s, &endptr, 10);
if (s == endptr) {
return false; // No conversion
}
if (errno == ERANGE) {
return false; // Outside long range
}
if (y < INT_MIN || y > INT_MAX) {
return false; // Outside int range
}
// Ignore trailing white space
while (isspace((unsigned char)*endptr)) {
endptr++;
}
if (*endptr) {
return false; // Trailing junk
}
return true;
}
bool isint\u alt(常量字符*s){
char*endptr;
errno=0;
长y=strtol(s和endptr,10);
如果(s==endptr){
返回false;//无转换
}
if(errno==ERANGE){
返回false;//超出远程范围
}
如果(yINT_MAX){
返回false;//超出int范围
}
//忽略尾随空白
while(isspace((未签名字符)*endptr)){
endptr++;
}
如果(*endptr){
返回false;//尾部垃圾
}
返回true;
}
strtol
将值转换为长int
,其范围可能不同于int
。此外,如果值可以转换,但超出了LONG int
的范围,则返回LONG\u MAX
或LONG\u MIN
。在这种情况下,errno
将设置为ERANGE
(但不是其他!),在匹配失败的情况下,返回的值为0,但未设置errno
;但是ep
指向字符串的开头
int isInt (char *s)
{
char *ep = NULL;
// zero errno first!
errno = 0;
long i = strtol (s, &ep, 10);
if (errno) {
return 0;
}
// matching failure.
if (ep == s) {
return 0;
}
// garbage follows
if (! ((*ep == 0) || (!strcmp(ep,"\n")))) {
return 0;
}
// it is outside the range of `int`
if (i < INT_MIN || i > INT_MAX) {
return 0;
}
return 1;
}
int-isInt(字符*s)
{
char*ep=NULL;
//零错误第一!
errno=0;
长i=strtol(s和ep,10);
如果(错误号){
返回0;
}
//匹配失败。
如果(ep==s){
返回0;
}
//垃圾接踵而至
如果(!((*ep==0)| |(!strcmp(ep,“\n”))){
返回0;
}
//它超出了'int'的范围`
如果(iINT_MAX){
返回0;
}
返回1;
}
不过,dbush关于使用perror
的说法是正确的strtol
仅在long
溢出的情况下设置错误,这不是函数中唯一可能的失败情况,因此peror
可以打印任何内容,如是目录
或多跳尝试
如果必须使用sscanf()
要检测int
溢出而不是健壮的strtol()
,有一种很麻烦的方法
使用较宽的字体和宽度限制,以防止扫描时溢出
bool isint_via_sscanf(const char *s) {
long long y;
int n = 0;
if (sscanf(s, "18%lld %n", &y, &n) != 1) { // Overflow not possible
return false; // Conversion failed
}
if (y < INT_MIN || y > INT_MAX) {
return false; // Outside int range
}
if (s[n]) {
return false; // Trailing junk
}
return true;
}
bool-isint\u通过sscanf(const-char*s){
长y;
int n=0;
如果(sscanf(s,“18%lld%n”、&y和&n)!=1){//不可能溢出
返回false;//转换失败
}
如果(yINT_MAX){
返回false;//超出int范围
}
如果(s[n]){
返回false;//尾部垃圾
}
返回true;
}
这在INT\u MAX>1e18
的罕见平台上是不够的
它还错误地返回无效的输入,如“大量前导空格和/或大量前导零000123”
使用sscanf()
的更复杂的代码可以解决这些缺点,但最好的方法是strto*()
忽略这一行。我将一些代码从isfloat()编辑为isInt(),peror()的第二次和第三次使用是没有意义的。因此,请花一点时间,正确地缩进代码。最好是num>INT\u MAX
永远都不是真的。由于num
是一个int
,它的值永远不会大于int\u MAX
。可能发生的情况是,当您输入一个大数字时,scanf
内部发生溢出(这可能是C标准没有定义的行为;我没有检查这个特定点),结果是int
中出现了一个负值。然后这触发了你的测试num<0
。我明白了。但我仍然有一个疑问。在输入long int之后,我必须与int_MAX进行比较,以检查int的overfow。然后当我输入long int时,我必须检查long long int。如果我输入long long int,那么我如何检查溢出。我的意思是,这里我想要int输入,所以我把它放在long int变量中,并用int_MAX检查它。但是,当我想要long long int时,那么
bool isint_via_sscanf(const char *s) {
long long y;
int n = 0;
if (sscanf(s, "18%lld %n", &y, &n) != 1) { // Overflow not possible
return false; // Conversion failed
}
if (y < INT_MIN || y > INT_MAX) {
return false; // Outside int range
}
if (s[n]) {
return false; // Trailing junk
}
return true;
}