在C++中,打印到控制台的最佳方式是什么?

16
我已经阅读了几个来源中关于在c++中向控制台打印输出的三种方法。以下是这三种方法:
  1. 使用 using namespace std; 然后使用 coutCodeBlocks Standard
  2. 不使用上述方式,而使用 std::coutstd::endl;C++ Primer
  3. 使用 printfHackerRank
哪种方法更好,为什么?

3
1和2其实是一样的。而且使用printf不是类型安全的。 - Some programmer dude
4
可能是['printf' vs. 'cout' in C++]的重复问题。 - user2201041
15
请,请不要试图从hackerrank学习C++。这将非常糟糕。 - Baum mit Augen
4
好的,请提供需要翻译的内容。 - user2201041
4
在全局作用域中使用 using namespace std 是不好的实践,因为它会导致命名空间污染(参见此处)。 - David
显示剩余8条评论
6个回答

22

第二条经修改后的建议。(使用std::cout'\n'

为什么?

  1. 应避免使用using namespace std参考来源
  2. (除其他原因外) 因为cout是类型安全的,而printf则不是。参考来源
  3. std::endl会强制刷新输出缓冲区到控制台。除非明确需要,否则请使用<< '\n'<< "...string\n"参考来源

6

如果你不太关心速度的话,cout和printf都可以。但如果你想要更快的运行时间,以下是一些指导:

  • 只使用printf而不使用cout。这比混合使用printf和cout或仅使用cout更快。
  • 或者只使用cout,但在执行之前添加以下内容:ios_base::sync_with_stdio(false);cin.tie(NULL);。printf和cout有两个独立的流,默认情况下它们是同步的。由于这种同步,很多运行时间都被浪费了。这两行代码将停止同步,但请注意,如果您添加了这些行,请不要使用任何printf,否则打印可能会随机发生。
  • 不要使用endl,除非你想刷新输出缓冲区。大量使用endl会使代码变慢。改用cout<<'\n';代替。

1
如果你想要速度,就不要打印。写入文件。 - Fantastic Mr Fox

1
这是我的调试器代码,它在我十年的C++工作中帮助了我。
std::ostream &debugRecord (const char* fileName, int lineNum, const char* funcName)
{
    std::lock_guard<std::mutex> lock(streamMutex_);
    return std::cout << "Thread # " << getCurrentThreadId() << " -- "
                     << "(" << fileName << ":" << lineNum << "): " << funcName << std::endl;
}

1
printf 对我来说做得不太好,让我感到困惑,所以我使用 cout 并获得了良好的结果。此外,<< 操作符也非常有帮助。 - Ehsan Panahi
你应该提到你使用的并发API需要哪些头文件(getCurrentThreadId()函数来自哪里?) - Peter - Reinstate Monica
getCurrentThreadId() 是我之前编写的一个函数。但如果您需要它,请告诉我在这里为您编写。 - Ehsan Panahi
不,这并非必须的;但你应该在回答中提到,并明确指出你的代码只是一个建议或模板,不能直接复制粘贴。尽管如此,我还是很喜欢它,即使原帖的问题可能更为普遍。 - Peter - Reinstate Monica
你为什么要使用 std::cout 进行调试,而不是专门提供给调试的 std::clog 呢?你真的不想让日志和程序输出混在一起吧! - Toby Speight

1
你的前两个观点基本上是一样的。最好使用std :: 而不是using namespace std; ,因为后者会污染全局命名空间并可能导致命名冲突。
没有提到的是,您可以使用using <namespace> :: <element>;(例如using std::cout;)选择性地公开命名空间的部分内容。仍然最好在语句中使用详细说明,但这个选项仍然不像公开整个命名空间那样糟糕。 printf 不如cout 安全(流<<运算符很好地打印了您想要的内容),您应该在刚开始学习时避免使用它。

特别是对于初学者,我建议不要使用 using namespace std;,而是每次都指定 std::,以便习惯这种代码阅读方式。但正如你所说,这可能会引起高度争议。 - KorbenDose
1
@AlexMeuer 在命名空间范围内的头文件中使用 using namespace … 几乎被普遍认为是不良实践,只是为了更具体一些。 - Arne Vogel

1
答案很大程度上取决于您想做什么。对于主要使用默认格式的输出,确实首选cout,因为它具有类型安全性并且非常直观。
如果您想大量格式化输出,我只能推荐令人惊讶地多才多艺和简单的printf,因为cout中的操作符是一种痛苦。确实:printf格式语法需要一些时间来适应,但这肯定是值得的。只需仔细检查格式字符串,听取编译器的警告,并使用适当的格式说明符,例如size_t和其他系统相关数据,以保持可移植性。
还有一种boost工具可以结合流和printf样式格式化,参见https://dev59.com/iWUp5IYBdhLWcg3wtZLt#15106194,但我从未使用过。也许有人可以评论其可用性?

0

2023年更新:

从C++23开始,控制台打印的惯用方式应该是使用std::print,它使用了{}占位符系统:

#include <print>

int main()
{
    std::print("{}, {} !", "Hello", "world");
}

然而,目前编译器对其的支持非常差。

与此同时,我们可以使用{fmt}库来实现类似的API。
需要注意的是,C++标准实际上是基于{fmt}的一个子集(大部分)。
在这里可以了解更多信息:libfmt和std::format之间的区别是什么?

工作示例:

#include <fmt/core.h>

int main()
{
    fmt::print("{}, {} !", "Hello", "world");
}

现场演示 - Godbolt

最后为了完整回答:为什么被认为"using namespace std;"是不好的做法?


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