在C语言中使用长度为char的缓冲区进行打印输出

28

我有一个缓冲区,通过串口接收数据。当我收到特定字符时,我知道一行数据已经接收完毕,并且我想使用printf方法打印它。但是每一行的长度值都不同,如果我只使用如下代码:

printf("%s", buffer);

我正在打印该行以及前一行的其他字符(如果前一行比当前行长)。

我在这里读到,至少在C++中,可以告诉你想要读取多少个字符,给定一个%s,但它没有示例,而且我不知道如何在C中实现。有什么帮助吗?

我认为我有三种解决方案:

  • 使用for循环逐个打印字符
  • 使用终止字符
  • 或者使用.*

问题是:哪一个更快?因为我正在处理微芯片PIC,并希望它尽可能快地完成。


2
当你已经收到了那个“特定字符”,并将其附加到buffer后,也要附加一个空字符(\0)。这会“告诉” sprintf() 何时停止打印字符。 - Linus Kleen
4个回答

62
你可以在终止字符后添加一个空字符,这样printf就能正常工作了。或者你也可以在printf语句中添加'.*'并提供长度。
printf("%.*s",len,buf);
在C++中,您可能会使用std::string和std::cout,像这样:
std::cout << std::string(buf,len);
如果您只想要最快的速度和无格式的输出,那么请使用:
fwrite(buf,1,len,stdout);

完美。所以我有三种解决方案:使用for循环逐个打印字符,使用终止字符或使用.* 问题是:哪一种更快?因为我正在处理微芯片PIC,我希望它能够快速完成。 - Roman Rdgz
@RomanRdgz:我的猜测是:fwrite 或者空终止符+fputs 应该是最快的,其次是空终止符+printf(可能会更慢,因为它可能需要解析格式字符串,除非编译器非常聪明),然后是带有 .*printf(肯定需要解析格式字符串),最后是逐个字符打印(可能是最慢的,因为所有函数调用都需要 - 不过这可能会被内联)。 - Matteo Italia
我正在使用CCS编译器,我不认为它有cout.write。这就是为什么我正在使用fputs或printf。谢谢你的信息@Matteo Italia - Roman Rdgz
如果您只想要最快的速度和无格式化 - 那么请使用 fwrite(buf,1,len,stdout) - Soren
翻译:PIC - 呃!无论如何,既然你知道已经到了行尾,在里面插入一个 null 并避免 printf 计数(只为使格式解析最少),这可能是最快的。你在打印什么? - Martin James
显示剩余3条评论

37
你所拥有的字符串没有以null结尾,因此,printf(和任何其他C字符串函数)无法确定其长度,因此它将继续写入找到的字符,直到它偶然遇到那里的null字符为止。
要解决问题,你可以选择以下方法之一: - 使用fwrite覆盖stdout:
fwrite(buffer, buffer_length, 1, stdout);

这个代码有效是因为fwrite不仅可以打印字符串,还可以打印其它类型的数据,所以它不会查找终止的空字符,而是接受要写入的数据长度作为参数;

  • 在打印之前需要手动添加空字符来终止缓冲区:

    buffer[buffer_length]=0;
    printf("%s", buffer); /* or, slightly more efficient: fputs(buffer, stdout); */
    

    如果您需要对buffer进行其他字符串处理操作,这可能是一个更好的方法,因为它现在已经以空字符结尾,可以使用普通的C字符串处理函数进行管理。


  • 1
    我很惊讶,这个 Stack Overflow 问题的重复答案中并没有包括这种方法,而只是建议使用 for 循环... - Alex

    3

    一旦您确定了行末尾,您必须在将其发送到printf之前,在缓冲区末尾添加一个'\0'字符。


    2
    有没有给我踩票的人想解释一下为什么,这样我就可以改进我的回答了吗? - Michael Price
    除了说明如何纠正,您还应该说出OP做错了什么。 - Alex

    3

    在接收到最后一个字符后,您可以在缓冲区中放置一个NUL(0x0)。

    buffer[i] = 0;


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接