- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在 x86_64 Linux 上使用 GCC 4.8 和 glibc 2.19。
在玩a different question的不同输入法时,我比较了 fscanf
和 sscanf
。具体来说,我会直接在标准输入上使用 fscanf
:
char s[128]; int n;
while (fscanf(stdin, "%127s %d", s, &n) == 2) { }
或者我会先将整个输入读入缓冲区,然后使用 sscanf
遍历缓冲区。 (将所有内容读入缓冲区需要很短的时间。)
char s[128]; int n;
char const * p = my_data;
for (int b; sscanf(p, "%127s %d%n", s, &n, &b) == 2; p += b) { }
令我惊讶的是,fscanf
版本的速度大大 更快。例如,使用 fscanf
处理几万行需要这么长时间:
10000 0.003927487 seconds time elapsed
20000 0.006860206 seconds time elapsed
30000 0.007933329 seconds time elapsed
40000 0.012881912 seconds time elapsed
50000 0.013516816 seconds time elapsed
60000 0.015670432 seconds time elapsed
70000 0.017393129 seconds time elapsed
80000 0.019837480 seconds time elapsed
90000 0.023925753 seconds time elapsed
现在与 sscanf
相同:
10000 0.035864643 seconds time elapsed
20000 0.127150772 seconds time elapsed
30000 0.319828373 seconds time elapsed
40000 0.611551668 seconds time elapsed
50000 0.919187459 seconds time elapsed
60000 1.327831544 seconds time elapsed
70000 1.809843039 seconds time elapsed
80000 2.354809588 seconds time elapsed
90000 2.970678416 seconds time elapsed
我使用 Google 性能工具来衡量这一点。例如,对于 50000 行,fscanf
代码需要大约 50M 周期,sscanf
代码大约需要 3300M 周期。因此,我使用 perf record
/perf report
分解了排名靠前的调用站点。使用 fscanf
:
35.26% xf libc-2.19.so [.] _IO_vfscanf
23.91% xf [kernel.kallsyms] [k] 0xffffffff8104f45a
8.93% xf libc-2.19.so [.] _int_malloc
和sscanf
:
98.22% xs libc-2.19.so [.] rawmemchr
0.68% xs libc-2.19.so [.] _IO_vfscanf
0.38% xs [kernel.kallsyms] [k] 0xffffffff8104f45a
所以几乎所有使用sscanf
的时间都花在了rawmemchr
上!为什么是这样? fscanf
代码如何避免这种开销?
我试着搜索这个,但我能想到的最好的是 this discussion锁定的 realloc
调用,我认为这里不适用。我还认为 fscanf
具有更好的内存局部性(反复使用相同的缓冲区),但这不会产生如此大的差异。
有人对这种奇怪的差异有任何见解吗?
最佳答案
sscanf() 将您传入的字符串转换为 _IO_FILE*
,使字符串看起来像一个"file"。这是因为相同的内部 _IO_vfscanf() 可用于字符串和 FILE*。
但是,作为该转换的一部分,它在 _IO_str_init_static_internal() 函数中完成,它调用 __rawmemchr (ptr, '\0');
本质上是对您的输入字符串的 strlen() 调用。每次调用 sscanf() 时都会进行此转换,并且由于您的输入缓冲区相当大,因此它将花费大量时间来计算输入字符串的长度。
使用 fmemopen() 从输入字符串创建一个 FILE* 并使用 fscanf() 可能是另一种选择。
关于c - 为什么 glibc 的 sscanf 在 Linux 上比 fscanf 慢很多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23923924/
这个问题不太可能对任何 future 的访客有帮助;它只与一个较小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于全世界的互联网受众。如需帮助使此问题更广泛适用,visit the
我在程序中遇到了以下行。通过阅读手册,我知道 sscanf 从 argv[2] 指向的任何地方复制,但我不确定为什么格式被指定为 %d,同时指定为 %c (我见过其他双引号中包含更多格式说明符的示例)
我可以使用字符指针 (char *) 作为 sscanf() 函数中的输出字符串吗?考虑到我不知道字符串的长度(这就是我使用指针的原因)。 char *name; sscanf(data, "Name
我有一个表单的输入字符串 char *s = "one.two three" 我想把它分成 3 个字符串变量。我在做 sscanf(s, "%s.%s %s", one, two, three); 但
我一直在尝试让 sscanf 使用字符类识别一种相当简单的格式。我注意到,当我为 sscanf 提供 char* 以匹配字符类时,它也会覆盖前一个字节,就好像它需要一个指向 2 个字节的指针一样。 我
我正在将 MAC 地址的字符串表示形式转换为 UINT8 的数组s 定义为 unsigned char 。我很好奇为什么sscanf()当我读入 UINT8 数组时,将读取全 0当我读入常规 32 位
我有一个包含空格和标签的字符串,例如: sp|P02671|FIBA_HUMAN Fibrinogen alpha chain OS=Homo sapiens GN=FGA PE=1 SV=2 我只想
我正在尝试在 C 中使用 sscanf 函数,但它不读取格式是必需的,我已经阅读了该函数的文档并遵循了示例,但它对我来说仍然效果不佳,因此我想要一些建议.. int main() { long i
我需要在c中解析一个格式为“foo=%d”的字符串,我需要检查格式是否正确并读取int值。 我的初始代码是: int foo_set = 0; int foo; if (sscanf(text, "f
在下面的代码中,我想读取十六进制字符串 'a' 中的前 2 个字符,使用 sscanf 将它们转换为相应的字节值并将结果放入 'b'。不应对“a”执行任何修改。 #include #include
我试图找出我应该给 sscanf 的模式。 我有一个字符串 abcde(1GB)。我想提取 1 和 GB。我在用 char list[]= "abcde(1GB)"; int memo
我应该得到一个可以是以下任何格式的输入行: 单词 1 和单词 2 之间必须有空格。 单词 2 和单词 3 之间必须有逗号。 单词 2 和单词 3 之间不一定要有空格,但可以有任意数量的空格。 如何分离
最近发现的对 GTA 冗长加载时间 (1) 的解释表明 sscanf() 的许多实现调用 strlen()在他们的输入字符串上为与其他扫描函数( scanf() , fscanf() ...)共享的内
我需要将字符串分成两部分,字符串的第一列是第一部分,字符串的其余部分是第二部分。第一部分需要存储在 first_str 中,第二部分需要存储在 rest_str 中。 我正在使用 sscanf 来实现
我需要从char数组中提取数字,它以hh:mm的格式存储值(示例20:20) 我尝试使用sscanf函数将hh提取为小时变量,将mm提取为分钟变量。 直到时间类似于0number:0number或如果
所以我想知道 sscanf 在遇到像这样的行时是如何工作的: sscanf(input_string, "%s %s %s", cmd1, cmd2, cmd3); 但是假设 input_string
我在以下代码中遇到 sscanf() 问题: void num_check(const char*ps){ char *ps1=NULL; int number=0; unsigned sum_num
谁能解释一下为什么在下面的代码中没有拆分字符串 #include int main(void) { char name[] = "first:last"; char first[20
我正在尝试解析一个 URL,并编写了这段代码: #include int main() { char host[100]; char port[100]; char path
我正在为我正在制作的程序使用 AT 命令,但在使用 sscanf() 函数解析它们时遇到问题。 例如,如果我执行此命令: "AT\r\r\nOK\r\n" 我想:* 在第一次调用时,仅获取“AT”部分
我是一名优秀的程序员,十分优秀!