sscanf()
的调用会在其输入字符串上调用strlen()
以设置用于与其他扫描函数(scanf()
、fscanf()
等)共享的内部例程的上下文对象。当输入字符串非常长时,这可能成为性能瓶颈。使用偏移量和%n
转换重复调用sscanf()
解析作为字符串加载的10MB JSON文件被证明是导致加载时间过长的主要原因。
我的问题是,sscanf()
是否应该读取超出完成转换所需的字节的输入字符串?例如,以下代码是否会引发未定义行为:
int test(void) {
char buf[1] = { '1' };
int v;
sscanf(buf, "%1d", &v);
return v;
}
该函数应返回
1
,并且不需要从buf
读取超过一个字节,但是sscanf()
是否允许从buf
读取超过第一个字节?
(1) JdeBP提供的参考资料:
https://nee.lv/2021/02/28/How-I-cut-GTA-Online-loading-times-by-70/
https://news.ycombinator.com/item?id=26297612
https://github.com/biojppm/rapidyaml/issues/40
strlen
而不是“仅仅”等待\0
,是因为如果你将sscanf
嵌套在其余*scanf
家族的正常机制上,显而易见的实现方法会使用一个基于已扫描字符串的伪FILE
对象。这是因为一个FILE
对象通常包括一个计数器和一个返回EOF
的方式,而其他代码正在期望这些内容。(换句话说,查找\0
而不是EOF
或者将\0
懒惰地转换为EOF
需要更复杂的改动。) - Steve Summit'\0'
并不需要进行涉及重做的工作。我已经在自己的实现中这样做了。'\0'
不能是数字的一部分,因此在数字解析器中不需要进行任何更改。其他解析器也很容易适应。对任意长字符串调用strlen()
是不可接受的。 - chqrliesscanf()
是否应该读取超过所需字节以完成转换的输入字符串?”这些问题可能会有不同的答案。我个人认为,sscanf
需要以空字符结尾的字符串作为输入是完全可以接受的,但在消耗任何字节之前就寻找任意长的字符串的末尾仍然是一个质量问题。 - trent