例如:
int main()
{
errno = 0;
printf("val = %lu err: %d\n", strtoul("12345678901234", NULL, 10), errno);
}
输出:
val = 1942892530错误:0
手册页说strtoul()应该返回ULONG_MAX(4294967295UL)的溢出值,有人可以解释strtoul()在这种情况下不返回ULONG_MAX的原因吗?
答案 0 :(得分:2)
如果你所在的系统unsigned long
使用64位,而int只使用32位,如果你没有包含stdlib.h
,编译器会认为strtoul
是一个函数返回一个int
值。
在这种情况下,strtoul("12345678901234", NULL, 10)
将返回12345678901234L
或十六进制0xb3a73ce2ff2
。假设函数返回一个int,它将转换为32位int。这种转换是实现定义的,并且通用实现只保留32个低位,这将给出0x73ce2ff2
或十进制1942892530
。您传递一个32位的int,其中64位是预期的,因此结果是未定义的,但是常见的实现只是使用堆栈中的下一个值来完成该值。由于我假设您的实现是小端,并且下一个值为0,因为errno
在前一行设置为0,并且参数的评估顺序未定义,因此您仍然获得1942892530
as一个无符号的长。堆栈中的下一个值恰好也是0。
TL / DR:由于您没有包含stdlib.h
并忽略了编译器警告,编译器认为strtoul
应该返回int
。另外,函数的参数的评估顺序明确地未通过标准指定。从那以后,你调用未定义的行为,一切都可以打印出来。
你应该从中学到什么:
答案 1 :(得分:1)
在调用 errno
之前,strtoul
的值很可能是。
参数评估的顺序是unspecified:
任何C运算符的操作数的评估顺序,包括函数调用表达式中函数参数的评估顺序,以及任何表达式中子表达式的评估顺序都是未指定的(除非另有说明)。编译器将以任何顺序对它们进行评估,并且可以在再次评估相同的表达式时选择另一个顺序 ....
标准有以下例子:
在函数调用中
(*pf[f1()]) (f2(), f3() + f4())
可以按任何顺序调用函数
f1
,f2
,f3
和f4
。在调用pf[f1()]
指向的函数之前,必须完成所有副作用。