最近在回答另一个问题时,我发现了代码存在的问题:
int n;
scanf ("%d", &n);
使用 strtol
函数可以检测溢出,因为在溢出时,最大允许值将被插入到 n
中,并且根据 C11 7.22.1.4
的规定将 errno
设置为指示溢出的值,如下所示:
如果正确的值超出了可表示值的范围,则返回LONG_MIN,LONG_MAX,LLONG_MIN,LLONG_MAX,ULONG_MAX或ULLONG_MAX(根据值的返回类型和符号,如果有任何值),并且将ERANGE的宏值存储在 errno 中。
然而,在涉及 scanf
的标准部分中,特别是 C11 7.21.6.2
节,我们看到:
如果该对象没有适当的类型,或者如果转换的结果不能表示在对象中,则行为是未定义的。
现在对我来说,这意味着可以返回 任何 值,并且没有提到设置 errno
的任何内容。这一点之所以引起注意,是因为上面链接的问题的提问者正在将 9,999,999,999
输入到 32 位 int
中,并得到了 1,410,065,407
,一个值,比类型的极限小了 233
,这表明它只是在类型的限制处绕回了。
当我尝试时,我得到了返回值为最大可能的 32 位无符号值 2,147,483,647
。
所以我的问题如下。当使用 scanf
函数系列时,如何以可移植的方式检测整数溢出?这是可能的吗?
现在我应该提到,在我的系统(Debian 7)中,在这些情况下实际上将 errno
设置为 ERANGE
,但我在标准中找不到任何强制执行此操作的内容。另外,scanf
的返回值为 1
,表示成功扫描该项。
errno
在这里不能很好地工作的一个原因:scanf
可以有各种转换。errno
适用于哪些转换?(如果设置errno
等同于转换失败,那将是明确的,但显然情况并非如此,即使在strtol
中也不是如此。) - M Oehm