C 如果LONG_MAX为2147483647,strtol(";-2147483648";,0,0)是否溢出?
根据标准规范: 如果主题序列具有预期的形式,且base的值为0,则从第一个数字开始的字符序列应解释为整数常量。如果主题序列具有预期的形式,且基数的值介于2和36之间,则应将其用作转换的基数,将每个字母的值归因于上文给出的值。如果主题序列以减号开头,则转换产生的值应为负数。如果endptr不是空指针,则指向最终字符串的指针应存储在endptr指向的对象中 当前的问题是,在求反之前,该值不在C 如果LONG_MAX为2147483647,strtol(";-2147483648";,0,0)是否溢出?,c,language-lawyer,integer-overflow,C,Language Lawyer,Integer Overflow,根据标准规范: 如果主题序列具有预期的形式,且base的值为0,则从第一个数字开始的字符序列应解释为整数常量。如果主题序列具有预期的形式,且基数的值介于2和36之间,则应将其用作转换的基数,将每个字母的值归因于上文给出的值。如果主题序列以减号开头,则转换产生的值应为负数。如果endptr不是空指针,则指向最终字符串的指针应存储在endptr指向的对象中 当前的问题是,在求反之前,该值不在long范围内。例如,在C89中(整数常量不能采用long-long),写入-2147483648可能是溢出;
long
范围内。例如,在C89中(整数常量不能采用long-long
),写入-2147483648
可能是溢出;您必须编写(-2147483647-1)
或类似代码
由于使用“integer constant”的措辞可以解释为对整型常量的类型应用C规则,因此这可能足以避免我们在这里出现未定义的行为,但同样的问题(没有这样容易解决的问题)也适用于strtoll
编辑:最后,请注意,即使溢出,也应返回“right”值。因此,这个问题实际上只是关于在这种情况下是否可以或必须设置
errno
。在32位平台上-2147483648
不是c89下的溢出,它对于和errno==0来说是很长的时间
直接引用标准
返回值
成功完成后,strtol()返回转换后的值,如果
任何如果无法执行任何转换,则返回0,并可能返回errno
设置为[EINVAL]。如果正确的值超出
返回可表示的值,LONG_MAX或LONG_MIN(根据
值的符号),并且errno设置为[ERANGE]
测试时,这似乎符合以下测试:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
int main(int argc, char *argv[]) {
long val = strtol(argv[1], NULL, 10);
fprintf(stderr, "long max: %ld, long min: %ld\n", LONG_MAX, LONG_MIN);
fprintf(stderr, "val: %ld, errno: %d\n", val, errno);
perror(argv[1]);
return 0;
}
生成以下输出:
$ ./foo -2147483648
long max: 2147483647, long min: -2147483648
val: -2147483648, errno: 0
-2147483648: Success
$ ./foo -2147483649
long max: 2147483647, long min: -2147483648
val: -2147483648, errno: 34
-2147483649: Numerical result out of range
尽管我不能指出今天标准中的一点特殊措辞,但当我在20世纪90年代为4BSD编写
strtol
时,我非常确定这不应该设置errno
,并且确保我不会。无论这是基于标准中的措辞,还是与某人的个人讨论,我都不记得了
为了避免溢出,这意味着必须非常小心地进行计算。我在unsigned long
中做了这件事,并在各种BSD的libc
源代码中包含了这条评论:
在某种程度上,我对C语言库中的这个动作和语言本身的语法之间的不对称感到恼火(在这种情况下,负数是两个独立的标记,
-
后跟数字,所以写-217483648
意味着-(217483648)
,变成-(217483648U)
这当然是217483648U
,因此是正的!(当然,假设是32位int
;问题值因其他位大小而异。)为什么不将问题更新为仅运行代码无法确定的问题,而不是仅在底部进行编辑。这样的问题本质上无法仅通过运行代码来回答。这是一个关于C语言要求的问题(请参见语言律师
标签)这个问题是在comp.std.c这里提出的,c委员会成员劳伦斯·琼斯说,errno
没有设置为ERANGE
@R.。我建议你将问题的标题改为测试无法完成的内容,你只需在底部进行编辑。标题是溢出一词的正确用法。在大多数c例如,“X溢出了吗?”可以通过测试得到肯定的回答,但不能得到否定的回答;因为溢出通常会导致未定义的行为,测试永远无法确定溢出没有发生。在strtol
的情况下,“溢出”如果发生这种情况,将是实现内部的,并且函数需要通过errno
报告,因此这应该可以在任何方向进行测试,但是测试不是回答关于C语言的问题,而是关于特定实现的问题,该实现可能是正确的,也可能是不正确的。
$ ./foo -2147483648
long max: 2147483647, long min: -2147483648
val: -2147483648, errno: 0
-2147483648: Success
$ ./foo -2147483649
long max: 2147483647, long min: -2147483648
val: -2147483648, errno: 34
-2147483649: Numerical result out of range
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set 'any' if any `digits' consumed; make it negative to indicate
* overflow.
*/