【问题标题】:What is the difference between printf() and puts() in C?C中的printf()和puts()有什么区别?
【发布时间】:2011-01-28 02:37:05
【问题描述】:

我知道您可以使用printf()puts() 进行打印。我还可以看到printf() 允许您插入变量并进行格式化。

puts() 仅仅是printf() 的原始版本。是否应该将其用于所有可能的printf() 而不使用字符串插值?

【问题讨论】:

  • 只是关于使用 printf 而不是 puts 的注释:永远不要使用 printf(variable) 来打印字符串。使用puts(variable)printf("%s', variable)。使用变量格式字符串存在安全风险:如果变量可以被攻击者写入,他们就可以使用格式字符串攻击程序。

标签: c string output printf puts


【解决方案1】:

putsprintf 简单,但请注意前者会自动附加换行符。如果这不是你想要的,你可以fputs你的字符串到标准输出或使用printf

【讨论】:

  • 我认为提及 printf 用于将附加变量添加到输出字符串中的附加参数也很重要。
【解决方案2】:

(Zan Lynx 在评论中指出了这一点,但我认为值得一提——因为接受的答案没有提及)。

puts(mystr);printf(mystr); 的本质区别在于后者的参数被解释为格式化字符串。如果字符串不包含任何控制字符 (%),结果通常是相同的(除了添加的换行符)但如果你不能依赖它(如果 mystr 是一个变量而不是文字)你应该使用它。

因此,将动态字符串作为 printf 的单个参数传递通常是危险的 - 并且在概念上错误

  char * myMessage;
  // ... myMessage gets assigned at runtime, unpredictable content
  printf(myMessage);  // <--- WRONG! (what if myMessage contains a '%' char?) 
  puts(myMessage);    // ok
  printf("%s\n",myMessage); // ok, equivalent to the previous, perhaps less efficient

这同样适用于 fputsfprintf(但 fputs 不添加换行符)。

【讨论】:

  • 以何种方式使用printf() 会降低效率?在运行时?在编译时?
  • @franklin 在运行时,因为printf 需要解析格式字符串。但是,这通常应该是无关紧要的。此外,一个聪明的编译器可以对此进行优化,并将printf替换为对puts的调用
【解决方案3】:

除了格式化,puts 如果成功则返回一个非负整数,如果不成功则返回EOF;而printf 返回打印的字符数(不包括结尾的空值)。

【讨论】:

  • 当我对此进行测试时, puts 返回字符串中包含终止字符的字符数,而 printf 返回不包含终止字符的打印字符数。这在技术上与您的定义一致,因为前者是一个非负整数,但我不确定这是否是您的意思。
  • @lou,你确定额外的包括来自空终止符而不是'\n'吗?
【解决方案4】:

在简单的情况下,编译器将对printf() 的调用转换为对puts() 的调用。

例如下面的代码会被编译成我接下来展示的汇编代码。

#include <stdio.h>
main() {
    printf("Hello world!");
    return 0;
}
push rbp
mov rbp,rsp
mov edi,str.Helloworld!
call dword imp.puts
mov eax,0x0
pop rbp
ret

在这个例子中,我使用了 GCC 版本 4.7.2 并使用 gcc -o hello hello.c 编译了源代码。

【讨论】:

  • 那么在标准输出中放置位置的新行呢?
  • 应该是printf("Hello world!\n"); gcc 确实将其转换为puts。由于这是一条旧消息,我将自己编辑。
  • 编译完C代码后怎么看汇编代码的?
  • @KorayTugay : gcc 的 -save-temps 选项可以做到这一点
  • 您也可以使用 gdb 之类的工具来反汇编二进制文件。
【解决方案5】:
int puts(const char *s);

puts() 将字符串 s 和尾随换行符写入标准输出。

int printf(const char *format, ...);

printf() 函数将输出写入标准输出,在格式字符串的控制下,该字符串指定后续参数如何转换为输出。

我会借此机会请您阅读文档。

【讨论】:

    【解决方案6】:

    根据我的经验,printf()puts() 包含更多的代码,无论格式字符串如何。

    如果我不需要格式化,我不使用printf。但是,fwritestdout 的工作速度比 puts 快很多。

    static const char my_text[] = "Using fwrite.\n";
    fwrite(my_text, 1, sizeof(my_text) - sizeof('\0'), stdout);
    

    注意:对于 cmets,'\0' 是一个整数常量。如 cmets 所示,正确的表达式应该是 sizeof(char)

    【讨论】:

    • "fwrite 到 stdout 的工作速度比 put 快得多。" - 可能是什么原因?
    • @AntonyHatchkins 通常不会“快很多”。但是,puts() 每次都必须对字符串执行 strlen() 调用,而如果使用 fwrite() 知道大小,则可以避免。这几乎是造成性能差异的唯一真正原因。
    • 这个答案不正确。 '\0' 的类型为 int,因此在大多数系统上,这将打印 Using fwrit。如果您想少打印 1 个字节,只需使用 1。sizeof (char),这可能是您在这里想要的,保证为 1。
    【解决方案7】:

    没错,printf 可以被认为是puts 的更强大版本。 printf 提供了格式化 变量以使用格式说明符(例如%s%d%lf 等...

    【讨论】:

      【解决方案8】:

      printf() 函数用于将字符串和变量打印到屏幕上,而 puts() 函数只允许您将字符串打印到屏幕上。

      【讨论】:

        【解决方案9】:

        puts 是一个简单的选择,在末尾添加一个新行,printf从格式化字符串写入输出。

        请参阅puts 的文档 对于printf

        我建议只使用printf,因为这比切换方法更一致,即如果您正在调试,搜索所有 printfs 比putsprintf 更容易。大多数情况下,您还想在打印输出中输出一个变量,因此puts 主要用于示例代码。

        【讨论】:

          【解决方案10】:

          比较puts()printf() 时,即使它们的内存消耗几乎相同,puts() 也比printf() 花费更多时间。

          【讨论】:

          • 请在您的答案中添加一些解释,以便其他人可以从中学习 - 您是否有可靠的来源证明这一说法?或者有什么原因可以解释这种差异?
          猜你喜欢
          • 1970-01-01
          • 2013-01-18
          • 1970-01-01
          • 2011-06-28
          • 1970-01-01
          • 2017-04-18
          • 1970-01-01
          • 2010-10-11
          • 1970-01-01
          相关资源
          最近更新 更多