注意:我完全修改了该问题,以更正确地反射(reflect)我为赏金设置的内容。请原谅可能与该答案产生的所有不一致之处。我不想创建一个新问题,因为以前对此的回答可能会有所帮助。

我正在努力实现C标准库,并对标准的一个特定方面感到困惑。

该标准根据scanfstrtolstrtoul的定义,定义了strtod函数家族接受的数字格式(%d,%i,%u,%o,%x)。

该标准还规定fscanf()仅将最多一个字符放回输入流,因此strtol不接受strtoulstrtodfscanf接受的某些序列(ISO/IEC 9899:1999,脚注251)。

我试图找到一些可以体现出这种差异的值(value)观。事实证明,十六进制前缀“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
*/

最佳答案

在comp.std.c上与PL22.11(ANSI“C”)的副字符Fred J.Tydeman的通信对此有所了解:

fscanf



这使“0x”成为匹配输入序列前缀的最长序列。 (即使是%i转换,因为十六进制“0x”的序列比十进制“0”的序列还要长。)



这使fscanf读取“z”,并将其放回不匹配的位置(遵守脚注251的一个字符的推回限制)。



这会使“0x”不匹配,即fscanf应该不分配任何值,返回零(如果%x%i是第一个转化说明符),而将“z”保留为输入流中的第一个未读字符。

strtol
strtol(和strtoul)的定义在一个关键点上有所不同:



这意味着strtol应该寻找最长的有效序列,在这种情况下为“0”。它应该将endptr指向“x”,并返回零。

关于c - 解析数字时scanf()和strtol()/strtod()之间的区别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1425730/

10-11 15:32