简体   繁体   English

fscanf中“读取字符数”的范围是多少?

[英]What is the range of the “number of characters read” in fscanf?

fscanf() specifies the "%n" directive as a means to write "the number of characters read from the input stream so far by this call to the fscanf function" C11dr §7.21.6.2 12. fscanf()指定"%n"指令作为写入“到目前为止通过对fscanf函数的调用从输入流读取的字符数”的方法“C11dr§7.21.6.212。

Let us call this number: ncount . 我们称这个号码为: ncount


The "%n" directive may be preceded by length modifiers hh, h, l, ll, j and others. "%n"指令可以在长度修饰符hh, h, l, ll, j等之后。 Examples: 例子:

FILE *stream = stdin;
int n_i;
fscanf(stream, "%*s%n", &n_i);    // save as int
signed char n_hh;
fscanf(stream, "%*s%hhn", &n_hh); // save as signed char
long long n_ll;
fscanf(stream, "%*s%lln", &n_ll); // save as long long

What is type or the minimal expected range of ncount ? 什么是ncount类型或最小预期范围?
What happens, or should happen, when "the number of characters read from the input stream" is large ? 当“从输入流中读取的字符数” 很大时会发生或应该发生什么?

My findings: 我的发现:
The C spec appears quiet on the definition of the minimal range/type of ncount . 对于ncount的最小范围/类型的定义,C规范显得很安静。 ncount is usually saved via "%n" which specifies an int destination though not an int source . ncount通常通过"%n"保存,它指定一个int 目标但不是int

By experimentation, ncount appears to be treated like an int or long on my platform - no real surprise there. 通过实验, ncount似乎在我的平台上被视为intlong在那里没有真正的惊喜。 (My int/long/long long are 4/4/8 bytes.) When saving ncount to a long long , the value saved does not exceed INT_MAX/LONG_MAX . (我的int/long/long long是4/4/8字节。)将ncount保存为long long ,保存的值不会超过INT_MAX/LONG_MAX ncount could have been unsigned for twice the usable range when assigned to long long , yet, this is an extreme corner and perhaps not considered by implementors. 当分配给long longncount可以是unsigned的两倍可用范围,但是,这是一个极端的角落,实现者可能不会考虑它。

My tests below showed no extended range of ncount past an int range, even when saved as a long long . 我在下面的测试表明,即使long long保存,也没有超出int范围的ncount扩展范围。

My interest stemmed from using "%*[^\\n]%lln" to determine a (extreme) line length. 我的兴趣源于使用"%*[^\\n]%lln"来确定(极端)线长。


Implementation notes: 实施说明:

GNU C11 (GCC) version 6.4.0 (i686-pc-cygwin) compiled by GNU C version 6.4.0, GMP version 6.1.2, MPFR version 3.1.5-p10, MPC version 1.0.3, isl version 0.14 or 0.13 GNU C11(GCC)版本6.4.0(i686-pc-cygwin),由GNU C版本6.4.0,GMP版本6.1.2,MPFR版本3.1.5-p10,MPC版本1.0.3编译,isl版本0.14或0.13

glibc 2.26 released. glibc 2.26发布。

Intel Xeon W3530, 64-bit OS (Windows 7) Intel Xeon W3530,64位操作系统(Windows 7)


Test code 测试代码

#include <limits.h>
#include <stdio.h>
#include <string.h>

int print(FILE *stream, long long size, int ch) {
  char buf[4096];
  memset(buf, ch, sizeof buf);
  while (size > 0) {
    size_t len = size < (long long) sizeof buf ? (size_t) size : sizeof buf;
    size_t y = fwrite(buf, 1, len, stream);
    if (len != y) {
      perror("printf");
      return 1;
    }
    size -= len;
  }
  return 0;
}

int scan(FILE *stream) {
  rewind(stream);
  long long n = -42;
  int cnt = fscanf(stream, "%*s%lln", &n);
  printf("cnt:%d n:%lld ", cnt, n);
  return cnt != 0;
}

int testf(long long n) {
  printf("%10lld ", n);
  FILE *f = fopen("x.txt", "w+b");
  if (f == NULL) {
    perror("fopen");
    return 1;
  }
  if (print(f, n, 'x')) {
    perror("print");
    fclose(f);
    return 2;
  }
  if (scan(f)) {
    perror("scan");
    fclose(f);
    return 3;
  }
  fclose(f);
  puts("OK");
  fflush(stdout);
  return 0;
}

int main(void) {
  printf("%d %ld %lld\n", INT_MAX, LONG_MAX, LLONG_MAX);
  testf(1000);
  testf(1000000);
  testf(INT_MAX);
  testf(INT_MAX + 1LL);
  testf(UINT_MAX);
  testf(UINT_MAX + 1LL);
  testf(1);
  return 0;
}

Test output 测试输出

2147483647 2147483647 9223372036854775807

File length      Reported bytes read
      1000 cnt:0 n:1000 OK
   1000000 cnt:0 n:1000000 OK
2147483647 cnt:0 n:2147483647 OK
2147483648 cnt:0 n:-2147483648 OK  // implies ncount is internally an `int/long`
4294967295 cnt:0 n:-1 OK
4294967296 cnt:0 n:-1088421888 OK  // This `n` value may not be consistent. -1 also seen
         1 cnt:0 n:1 OK

[Edit] [编辑]

With some runs of testf(UINT_MAX + 1LL); 运行一些testf(UINT_MAX + 1LL); , I received other inconsistent results like '4294967296 cnt:0 n:1239482368 OK'. ,我收到了其他不一致的结果,如'4294967296 cnt:0 n:1239482368 OK'。 Hmmmm. Hmmmm。

Sample fscanf() support source code uses an int for ncount . 示例fscanf() 支持源代码ncount使用int

What is type or the minimal expected range of ncount? 什么是ncount的类型或最小预期范围?

The standard does not specify any specific minimum. 该标准没有规定任何具体的最低要求。 It flatly says 断然说道

The corresponding argument shall be a pointer to signed integer into which is to be written the number of characters read from the input stream so far by this call to the fscanf function. 相应的参数应该是一个指向有符号整数的指针,到目前为止,通过调用fscanf函数将写入从输入流中读取的字符数。

( C2011, 7.21.6.2/12 ) C2011,7.21.6.2/12

This leaves no room for a conforming implementation to store a different number in the destination variable, except inasmuch as the standard specifies for all conversions, including %n , that 这使得一致的实现没有空间在目标变量中存储不同的数字,除非标准指定所有转换,包括%n

if the result of the conversion cannot be represented in the [destination] object, the behavior is undefined. 如果转换结果无法在[destination]对象中表示,则行为未定义。

( C2011 7.21.6.2/10 ) C2011 7.21.6.2/10

What happens, or should happen, when "the number of characters read from the input stream" is large? 当“从输入流中读取的字符数”很大时会发生或应该发生什么?

If the pointer corresponding to the %n directive is correctly typed for the directive's length specifier (or lack thereof), and if the true count of characters read up to that point by that scanf() call can be represented in an object of that type, then the true count should in fact be stored. 如果对于%n指令对应的指针正确地为指令的长度说明符(或缺少指针)键入,并且如果通过该scanf()调用读取到该点的真实字符数可以在该类型的对象中表示,那么真正的计数实际上应该存储。 Otherwise, the behavior is undefined. 否则,行为未定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM