【问题标题】:fputs() with newline like puts() in Cfputs() 与 C 中的 puts() 类似的换行符
【发布时间】:2018-12-18 23:43:59
【问题描述】:

在 C 中,puts(string); 会将string 打印到标准输出,然后是换行符。另一方面,fputs(fileptr, string); 会将string 写入fileptr,而没有尾随的换行符。有没有像 fputs() 这样附加换行符的函数,还是我应该像我一直在使用的那样坚持使用 fprintf(fileptr, "%s\n", string);?

fputs() 对我来说似乎比fprintf() 更有效,因为它不解析它的输入。我知道我也可以使用

fputs(string, fileptr);
fputc('\n', fileptr);

但我想知道是否有办法通过一次磁盘写入来做到这一点。

我试图弄清楚puts() 如何附加换行符(因为printf() 实际上只是vfprintf(stdout, ...) 的包装,我认为puts() 和fputs() 可能也是如此),但奇怪的是在 glibc 源代码中找不到 puts()。

【问题讨论】:

  • 似乎比 ... 您做了哪些分析显示两者之间存在显着差异,这是不可接受的,为什么?特别是因为磁盘 I/O,即使有缓冲,也比 CPU 周期长几个数量级?
  • 这两个函数调用(fputs(fileptr, string); 和 fputc(fileptr, '\n');)都是错误的。文件流参数位于最后,fprintf() 和 fscanf() 及其变体除外。因此,函数调用应该是fputs(string, fileptr); 和fputc('\n', fileptr);。

标签: c microbenchmark puts


【解决方案1】:

我想知道是否有办法通过一次磁盘写入来做到这一点。

您对事物进行了过度优化。对磁盘的写入是缓冲的,除非你碰巧弄乱了缓冲设置或者你使用了一个非常糟糕的 libc 实现。一般来说,实现你想要的最好的方法是

fputs(string, fileptr);
fputc('\n', fileptr);

放下手。如果你不关心优化,或你相信你的编译器会优化它,你可以使用

fprintf(fileptr, "%s\n", string);

它需要解析格式字符串 - 即便如此,在内部,使用等效的 fputs 来编写 %s 和 fputc 以打印换行符。


但是有一个问题 - 请注意 FILE 结构通常具有某种锁定以确保线程安全。 fputs + fputc 需要两次获取锁,而fprintf 可能只需要一次。然而,在单线程应用程序中,锁不会被争用。但可能只是对于复杂的格式和多线程程序,fprintf 解析比单独操作获取锁要快。另一个是来自另一个线程的调用可以交错fputs/fputc,但fprintf应该是原子的。


附: Glibc 的puts 代码在libio/ioputs.c 中。

【讨论】:

  • 这比 fprintf(fileptr, "%s\n", string); 好吗?
  • 你在@Billy 的杂草丛中。一个好的编译器可能会将两者优化为相同。这是实现定义的,但应该在编译器之间接近。关于缓冲的要点是 I/O 操作从 BUFSIZ 缓冲区读取和写入(请参阅:C 库源 IO_BUFSIZ(通常在 Linux 上为 8192,在 windows 上为 512)。所以从 I/O 的角度来看这将是一个基本的清洗。意识形态上的区别在于 fprintf 是一个 variadic 函数,与具有固定参数的函数相比,它通常具有额外的开销 - 但优化处理最多。
  • 有我正在寻找的链接,它现在在_G_BUFSIZ in Gnu libc (_G_config.h) 下(_IO_BUFSIZ 定义为_G_BUFSIZ 和BUFSIZ 定义为_IO_BUFSIZ 在单独的头文件中)
  • @DavidC.Rankin 感谢您的撰写。你好像在写,我用fprintf(fileptr, "%s\n", string);编译后在我的程序上运行了strings,我没有看到%s的任何出现。
  • 如果您需要将单个文件流上的操作组合在一起,POSIX 应用程序可以使用flockfile() 和funlockfile() 和ftrylockfile()。它们的设计目的是使flockfile(fp); fprintf(fp, "…", …); fprintf(fp, "…", …); funlockfile(fp); 保持两个fprintf() 操作的输出连续,而另一个线程没有机会插入其输出。
【解决方案2】:

没有什么比:

  1. 确保您的字符串可以多容纳一个字符
  2. 将\n分配给字符串
  3. fputs字符串

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-22
    • 1970-01-01
    相关资源
    最近更新 更多