Dev*_*lar 12 c standards standards-compliance
注意:我完全重写了这个问题,以更恰当地反映出我为此设置的赏金.请原谅与已经给出的答案有任何不一致之处.我不想创建一个新问题,因为之前的答案可能会有所帮助.
我正在努力实现一个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
*/
Run Code Online (Sandbox Code Playgroud)
与comp.std.c的PL22.11(ANSI"C")副主席Fred J. Tydeman的沟通对此有所了解:
fscanf
输入项被定义为输入字符的最长序列,它是匹配输入序列的前缀,或者是匹配输入序列的前缀.(7.19.6.2 P9)
这使得"0x"成为匹配输入序列的前缀的最长序列.(即使进行%i转换,十六进制"0x"的序列也比十进制"0"长.)
输入项目之后的第一个字符(如果有)仍未读取.(7.19.6.2 P9)
这使得fscanf读取"z",并将其作为不匹配(遵守脚注251的单字符后推限制)).
如果输入项不是匹配序列,则指令的执行失败:此条件是匹配失败.(7.19.6.2 P10)
这使得"0x"无法匹配,即fscanf不应分配任何值,返回零(如果%x或是%i第一个转换说明符),并将"z"保留为输入流中的第一个未读字符.
strtol
strtol(和strtoul)的定义在一个关键点上有所不同:
主题序列被定义为输入字符串的最长初始子序列,从第一个非空白字符开始,即预期形式.(7.20.1.4 P4,强调我的)
这意味着strtol应该寻找最长的有效序列,在本例中为"0".它应该指向endptr"x",并返回零作为结果.