我正在处理使用wcahr_t
类型字符的文件。我想让我的程序更快。
将fprintf
替换为fputwc
和fscanf
并尽可能用fgetwc
代替是否有意义?
如果是这样,为什么?
答案 0 :(得分:2)
我每次调用仅使用一个wchar_t
进行了一些快速分析,确实存在明显的差异。首先,代码:
#include "stdio.h"
#include "time.h"
#include "wchar.h"
wchar_t text[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#$";
const int N = 64;
const int M = 500000;
int main()
{
int i, j;
FILE *f1 = fopen("out1", "w");
FILE *f2 = fopen("out2", "w");
if (f1 == NULL || f2 == NULL)
{
printf("Failed to create file.\n");
return -1;
}
clock_t time1 = clock();
for (i = 0; i < M; i++)
for (j = 0; j < N; j++)
fprintf(f1, "%c", text[j]);
time1 = clock() - time1;
clock_t time2 = clock();
for (i = 0; i < M; i++)
for (j = 0; j < N; j++)
fputwc(text[j], f2);
time2 = clock() - time2;
printf("fprintf: %d ticks\nfputwc: %d ticks\n", time1, time2);
return 0;
}
gcc的输出:
fprintf:5663 ticks
fputwc:3307 ticks
clang的输出:
fprintf:4696 ticks
fputwc:3338 ticks
写入stdout或内存缓冲区具有相同的时差,因此这与它们如何写入或何时刷新等无关。它只是函数实现。我们来看看它们:
最明显的区别是fprintf
采用了必须解析的格式。因此,它必须做的最小工作是:
while (*fmt) {
if (*fmt++ == '%') {
switch (*fmt)
{
case 'c': *output = va_arg(args, int); break;
...
}
}
}
正如您所看到的,代码必须执行fputwc
不进行的多次检查和增量,这意味着额外的执行时间。 (见评论)这些差异可能会占用大部分额外时间。case 'c'
在其他情况下的位置实际上很重要,它越低,它就会越慢。
特别是在printf("%c", x)
的情况下,我们有:
'%'
进行比较 - 约5条说明在此之后,它与fputwc
几乎完全相同。每次通话所有这些额外的指令都会加起来。
还有一些其他因素可以影响这一点,例如传递额外的参数,但是一个好的编译器可以优化它。
所有这一切,这是一种非常低效的处理方式。您可能应该写入缓冲区,然后调用fwrite
(我的时钟与fputwc
类似)并在一次调用中转储整个缓冲区。需要注意的一点是,fwrite(f, sizeof(wchar_t), N, text);
实际上也会输出0个字节,最后是"a\0b\0c\0"
,依此类推。