注意: 我完全重新修订了问题,以更准确地反映我设置奖励的目的。请原谅这可能引起的任何与已有答案不一致的地方。我不想创建一个新的问题,因为先前对此的回答可能是有帮助的。
我正在实现一个C标准库,对于标准中的一个特定角落感到困惑。
标准定义了scanf
函数系列接受的数字格式(%d、%i、%u、%o、%x) 与 strtol
、strtoul
和 strtod
的定义相关联。
标准还指出,fscanf()
最多只会将一个字符放回输入流,因此一些可被strtol
、strtoul
和 strtod
接受的序列在fscanf
中是不可接受的(ISO / IEC 9899:1999,附注251)。
我试图找到一些能够显示这种差异的值。结果发现,十六进制前缀“0x”,后跟一个不是十六进制数位的字符,就是两个函数族之间差异的一种情况。
有趣的是,似乎没有两个可用的C库在输出上达成了一致。(请参见本问题末尾的测试程序和示例输出。)
我想要知道的是解析“0xz”的标准兼容行为是什么?理想情况下引用标准中的相关部分以支持观点。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main()
{
int i, count, rc;
unsigned u;
char * endptr = NULL;
char culprit[] = "0xz";
/* File I/O to assert fscanf == sscanf */
FILE * fh = fopen( "testfile", "w+" );
fprintf( fh, "%s", culprit );
rewind( fh );
/* fscanf base 16 */
u = -1; count = -1;
rc = fscanf( fh, "%x%n", &u, &count );
printf( "fscanf: Returned %d, result %2d, consumed %d\n", rc, u, count );
rewind( fh );
/* strtoul base 16 */
u = strtoul( culprit, &endptr, 16 );
printf( "strtoul: result %2d, consumed %d\n", u, endptr - culprit );
puts( "" );
/* fscanf base 0 */
i = -1; count = -1;
rc = fscanf( fh, "%i%n", &i, &count );
printf( "fscanf: Returned %d, result %2d, consumed %d\n", rc, i, count );
rewind( fh );
/* strtol base 0 */
i = strtol( culprit, &endptr, 0 );
printf( "strtoul: result %2d, consumed %d\n", i, endptr - culprit );
fclose( fh );
return 0;
}
/* newlib 1.14
fscanf: Returned 1, result 0, consumed 1
strtoul: result 0, consumed 0
fscanf: Returned 1, result 0, consumed 1
strtoul: result 0, consumed 0
*/
/* glibc-2.8
fscanf: Returned 1, result 0, consumed 2
strtoul: result 0, consumed 1
fscanf: Returned 1, result 0, consumed 2
strtoul: result 0, consumed 1
*/
/* Microsoft MSVC
fscanf: Returned 0, result -1, consumed -1
strtoul: result 0, consumed 0
fscanf: Returned 0, result 0, consumed -1
strtoul: result 0, consumed 0
*/
/* IBM AIX
fscanf: Returned 0, result -1, consumed -1
strtoul: result 0, consumed 1
fscanf: Returned 0, result 0, consumed -1
strtoul: result 0, consumed 1
*/
strto*
函数具有定义行为。然而,对于scanf()
,在接收到太大的值时行为是未定义的。因此,将12345678901234567890
输入到strtol()
将产生错误指示(假设sizeof(long) <= 8
),但是使用scanf()
等可能会发生任何事情。 - Jonathan Leffler