Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何处理整数溢出?_C_Int_Overflow - Fatal编程技术网

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;  
}