提问人:hero 提问时间:5/20/2010 最后编辑:Deduplicatorhero 更新时间:10/16/2021 访问量:485295
C++中的“printf”与“cout”
'printf' vs. 'cout' in C++
答:
我引用:
概括地说,主要区别在于类型安全(cstdio 没有)、性能(大多数 IOTream 实现都是 比 CSTDIO 慢)和可扩展性(IOTroStream 允许 自定义输出目标和用户定义类型的无缝输出)。
评论
一个是打印到 stdout 的函数。另一个对象提供多个成员函数和该打印的重载到 stdout。我可以列举更多的差异,但我不确定你在追求什么。operator<<
cout<< "Hello";
printf("%s", "Hello");
两者都用于打印值。它们具有完全不同的语法。C++ 两者兼而有之,C 只有 printf。
评论
来自 C++ 常见问题解答:
[15.1] 为什么我应该使用 <
iostream
>而不是传统的<cstdio>
?提高类型安全性、减少错误、允许扩展性并提供可继承性。
printf()
可以说没有损坏,尽管容易出错,但也许是宜居的,但是两者在 C++ I/O 可以做什么方面都受到限制。 C++ I/O(使用 和 )相对于 C(使用 和 ):scanf()
<<
>>
printf()
scanf()
- 类型更安全:使用 时,被 I/O 的对象类型是 编译器静态已知。在 对比度,使用“%”字段来 动态找出类型。
<iostream>
<cstdio>
- 更不容易出错:有了 ,就没有冗余 必须保持一致的“%”标记 实际对象是 I/O'd。 删除冗余会删除类 的错误。
<iostream>
- 可扩展:C++ 机制允许新的用户定义 类型是 I/O 而不中断 现有代码。想象一下混乱,如果 每个人都在同时添加 新的不兼容的“%”字段到 和 ?!
<iostream>
printf()
scanf()
- 可继承:C++ 机制是从真实类构建的 例如 和 。与 不同的是,这些是实数类和 因此是可继承的。这意味着您可以 具有其他用户定义的东西 看起来和行为都像溪流,但那 做任何奇怪和奇妙的事情 你想要的东西。你自动 开始使用数以百万计的行 由您不编写的用户编写的 I/O 代码 甚至知道,他们也不需要 了解您的“扩展流” 类。
<iostream>
std::ostream
std::istream
<cstdio>
FILE*
另一方面,速度要快得多,这可能证明在非常具体和有限的情况下优先使用它是合理的。始终将配置文件放在首位。(例如,参见 http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-coutprintf
cout
/)
评论
printf()
printf
人们经常声称这要快得多。这在很大程度上是一个神话。我刚刚测试了它,结果如下:printf
cout with only endl 1461.310252 ms
cout with only '\n' 343.080217 ms
printf with only '\n' 90.295948 ms
cout with string constant and endl 1892.975381 ms
cout with string constant and '\n' 416.123446 ms
printf with string constant and '\n' 472.073070 ms
cout with some stuff and endl 3496.489748 ms
cout with some stuff and '\n' 2638.272046 ms
printf with some stuff and '\n' 2520.318314 ms
结论:如果您只想要换行符,请使用 ;否则,几乎一样快,甚至更快。更多细节可以在我的博客上找到。printf
cout
需要明确的是,我并不是想说 s 总是比 ;我只是想说,你应该根据真实数据做出明智的决定,而不是基于一些常见的、误导性的假设的疯狂猜测。iostream
printf
更新:这是我用于测试的完整代码。编译时没有任何其他选项(除了时间)。g++
-lrt
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
timespec d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
clock_gettime(CLOCK_REALTIME, &d_start);
}
~TimedSection() {
timespec end;
clock_gettime(CLOCK_REALTIME, &end);
double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
std::cerr << d_name << '\t' << std::fixed << duration << " ms\n";
}
};
int main() {
const int iters = 10000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
}
评论
printf()
std::ostream
std::ostream
<<
printf
sprintf
fprintf
stringstream
fstream
对我来说,让我选择“cout”而不是“printf”的真正区别是:
1)<<运算符可以为我的类重载。
2) cout 的输出流可以很容易地更改为文件: (: 复制粘贴:)
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf());
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf);
cout << "This is also sent to prompt" << endl;
return 0;
}
3)我发现cout更具可读性,尤其是当我们有很多参数时。
一个问题是格式选项。格式化数据(精度、对齐等)更容易。cout
printf
评论
printf
fprintf
对于基元,使用哪一个可能并不完全重要。我说它有用的地方是当你想要输出复杂的对象时。
例如,如果您有一个类,
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// output with printf
printf("%i, %i, %i\n", s.a, s.b, s.c);
// output with cout
cout << s << endl;
return 0;
}
现在,上面的内容可能看起来不是那么好,但假设您必须在代码中的多个位置输出它。不仅如此,假设您添加了一个字段“int d”。使用 cout,您只需在一个地方更改它。但是,使用 printf,您必须在很多地方更改它,不仅如此,您还必须提醒自己要输出哪些位置。
话虽如此,使用 cout,您可以减少花在维护代码上的大量时间,不仅如此,如果您在新应用程序中重用对象“Something”,您实际上不必担心输出。
评论
当然,你可以把“一些东西”写得更好一点,以保持维护:
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
void print() const { printf("%i, %i, %i\n", a, b, c); }
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// Output with printf
s.print(); // Simple as well, isn't it?
// Output with cout
cout << s << endl;
return 0;
}
如果有人想做更多测试(Visual Studio 2008,可执行文件的发布版本),则对 cout 与 printf 进行了一些扩展测试,添加了“double”测试:
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
//timespec d_start;
clock_t d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
//clock_gettime(CLOCK_REALTIME, &d_start);
d_start = clock();
}
~TimedSection() {
clock_t end;
//clock_gettime(CLOCK_REALTIME, &end);
end = clock();
double duration = /*1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
*/
(double) (end - d_start) / CLOCKS_PER_SEC;
std::cerr << d_name << '\t' << std::fixed << duration * 1000.0 << " ms\n";
}
};
int main() {
const int iters = 1000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
{
TimedSection s("cout with formatted double (width & precision once)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
std::cout.width(8);
for (int i = 0; i < iters; ++i)
std::cout << text << 8.315 << i << '\n';
}
{
TimedSection s("cout with formatted double (width & precision on each call)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
for (int i = 0; i < iters; ++i)
{ std::cout.width(8);
std::cout.precision(3);
std::cout << text << 8.315 << i << '\n';
}
}
{
TimedSection s("printf with formatted double");
for (int i = 0; i < iters; ++i)
printf("%8.3f%i\n", 8.315, i);
}
}
结果是:
cout with only endl 6453.000000 ms
cout with only '\n' 125.000000 ms
printf with only '\n' 156.000000 ms
cout with string constant and endl 6937.000000 ms
cout with string constant and '\n' 1391.000000 ms
printf with string constant and '\n' 3391.000000 ms
cout with some stuff and endl 9672.000000 ms
cout with some stuff and '\n' 7296.000000 ms
printf with some stuff and '\n' 12235.000000 ms
cout with formatted double (width & precision once) 7906.000000 ms
cout with formatted double (width & precision on each call) 9141.000000 ms
printf with formatted double 3312.000000 ms
评论
endl
'\n'
endl
\n
template <class _Elem, class _Traits> basic_ostream<_Elem, _Traits> &__CLRCALL_OR_CDECL endl(basic_ostream<_Elem, _Traits> &_Ostr) { // insert newline and flush stream _Ostr.put(_Ostr.widen('\n')); _Ostr.flush(); return _Ostr; }
我想说的是,缺乏可扩展性并不完全正确:
在 C 语言中,这是真的。但是在 C 中,没有真正的类。
在 C++ 中,可以重载强制转换运算符,因此,重载运算符并像这样使用:printf
char*
printf
Foo bar;
...;
printf("%s",bar);
可以,如果 Foo 超载良好的操作员。或者如果你做了一个好方法。简而言之,对我来说是可扩展的。printf
cout
我可以看到 C++ 流的技术论据(一般来说......不仅是 cout。是:
类型安全。(而且,顺便说一句,如果我想打印一个,我使用......我不会用核弹来杀死昆虫。
'\n'
putchar('\n')
更简单易学。(没有“复杂”的参数要学习,只是使用和运算符)
<<
>>
本机工作(因为有 ,但对于?
std::string
printf
std::string::c_str()
scanf
因为我明白了:printf
更简单,或者至少更短(就所写的字符而言)复杂的格式。对我来说,可读性要强得多(我猜是品味问题)。
更好地控制函数的内容(返回写入的字符数,并且有格式化程序:“未打印任何字符。该参数必须是指向有符号 int 的指针,其中存储了到目前为止写入的字符数。(来自 printf - C++ 参考
%n
)更好的调试可能性。原因与上一个论点相同。
我个人偏爱(和)函数,主要是因为我喜欢短行,而且我认为打印文本上的打字问题真的很难避免。
我对 C 样式函数唯一感到遗憾的是不支持它。在给它之前,我们必须经过一个(如果我们想阅读,但如何写?printf
scanf
std::string
char*
printf
std::string::c_str()
评论
char*
char*
更多差异: “printf”返回一个整数值(等于打印的字符数),而“cout”不返回任何内容
和。
cout << "y = " << 7;
不是原子的。
printf("%s = %d", "y", 7);
是原子的。
Cout 执行类型检查,printf 不执行。
没有 iostream 等效项"% d"
评论
cout
不返回任何内容,因为它是一个对象,而不是一个函数。 确实返回某些内容(通常是它的左操作数,但如果有错误,则返回一个假值)。在什么意义上被称为“原子”?operator<<
printf
printf("%s\n",7);
%s
printf
printf
printf
printf
令我惊讶的是,这个问题中的每个人都声称这比 要好得多,即使这个问题只是要求差异。现在,有一个区别 - 是C++,是C(但是,您可以在C++中使用它,就像C中的几乎所有其他内容一样)。现在,我在这里说实话;两者都有其优势。std::cout
printf
std::cout
printf
printf
std::cout
真正的差异
扩展
std::cout
是可扩展的。我知道人们也会说这也是可扩展的,但是 C 标准中没有提到这样的扩展(所以你必须使用非标准功能——但甚至不存在常见的非标准功能),而且这样的扩展是一个字母(所以很容易与已经存在的格式发生冲突)。printf
与 不同,完全依赖于运算符重载,因此自定义格式没有问题 - 您所做的只是定义一个子例程,将您的类型作为第一个参数,将您的类型作为第二个参数。因此,没有命名空间问题 - 只要你有一个类(不限于一个字符),你就可以为它工作重载。printf
std::cout
std::ostream
std::ostream
但是,我怀疑很多人会想要扩展(老实说,我很少看到这样的扩展,即使它们很容易制作)。但是,如果您需要它,它就在这里。ostream
语法
很容易注意到,两者都使用不同的语法。 使用标准函数语法,使用模式字符串和可变长度参数列表。实际上,这是 C 拥有它们的一个原因——格式太复杂了,没有它们就无法使用。但是,使用不同的 API - 返回自身的 API。printf
std::cout
printf
printf
printf
std::cout
operator <<
一般来说,这意味着 C 版本会更短,但在大多数情况下这无关紧要。当您打印许多参数时,差异是显而易见的。如果您必须编写类似 ,假设错误号,并且其描述是占位符,则代码将如下所示。这两个示例的工作方式相同(嗯,有点,实际上刷新了缓冲区)。Error 2: File not found.
std::endl
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
虽然这看起来并不太疯狂(它只是长了两倍),但当你实际格式化参数时,事情会变得更加疯狂,而不仅仅是打印它们。例如,打印类似的东西简直太疯狂了。这是由混合状态和实际值引起的。我从未见过一种语言将类似的东西变成一种类型(当然,C++除外)。 清楚地将参数和实际类型分开。与它的版本相比,我真的更愿意维护它的版本(即使它看起来有点神秘)(因为它包含太多噪音)。0x0424
std::cout
std::setfill
printf
printf
iostream
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
译本
这才是真正的优势所在。格式字符串很好...一个字符串。与滥用 .假设函数进行转换,并且您想要显示 ,用于获取先前显示的格式字符串的转换的代码将如下所示:printf
printf
operator <<
iostream
gettext()
Error 2: File not found.
printf(gettext("Error %d: %s.\n"), id, errors[id]);
现在,让我们假设我们翻译成 Fictionish,其中错误号位于描述之后。转换后的字符串将类似于 。现在,如何在C++中做到这一点?好吧,我不知道。我想你可以为了翻译的目的而伪造哪些结构,你可以传递给 或其他东西。当然,不是 C 标准,但它是如此普遍,在我看来使用起来是安全的。%2$s oru %1$d.\n
iostream
printf
gettext
$
不必记住/查找特定的整数类型语法
C 有很多整数类型,C++ 也是如此。 为您处理所有类型,但需要特定的语法,具体取决于整数类型(有非整数类型,但您在实践中将使用的唯一非整数类型是(C 字符串,可以使用 )方法获取)。例如,要打印,您需要使用 ,而需要使用 。这些桌子在 http://en.cppreference.com/w/cpp/io/c/fprintf 和 http://en.cppreference.com/w/cpp/types/integer 有售。std::cout
printf
printf
const char *
to_c
std::string
size_t
%zu
int64_t
%"PRId64"
您不能打印 NUL 字节,\0
因为使用 C 字符串而不是 C++ 字符串,所以如果没有特定的技巧,它无法打印 NUL 字节。在某些情况下,它可以用作论据,尽管这显然是一种黑客攻击。printf
%c
'\0'
没人关心的差异
性能
更新:事实证明,它太慢了,它通常比你的硬盘驱动器慢(如果你将程序重定向到文件)。如果您需要输出大量数据,禁用同步可能会有所帮助。如果性能是一个真正的问题(而不是将几行写入 STDOUT),只需使用 .iostream
stdio
printf
每个人都认为他们关心绩效,但没有人费心去衡量它。我的回答是,无论如何,I/O 都是瓶颈,无论您使用 or 还是 .我认为通过快速查看汇编(使用编译器选项使用 clang 编译)可能会更快。假设我的错误示例,示例所做的调用比示例少得多。这是与:printf
iostream
printf
-O3
printf
cout
int main
printf
main: @ @main
@ BB#0:
push {lr}
ldr r0, .LCPI0_0
ldr r2, .LCPI0_1
mov r1, #2
bl printf
mov r0, #0
pop {lr}
mov pc, lr
.align 2
@ BB#1:
你可以很容易地注意到两个字符串和 (number) 被作为参数推送。仅此而已;没有别的了。为了进行比较,它被编译为汇编。不,没有内联;每个调用都意味着另一个具有另一组参数的调用。2
printf
iostream
operator <<
main: @ @main
@ BB#0:
push {r4, r5, lr}
ldr r4, .LCPI0_0
ldr r1, .LCPI0_1
mov r2, #6
mov r3, #0
mov r0, r4
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
mov r0, r4
mov r1, #2
bl _ZNSolsEi
ldr r1, .LCPI0_2
mov r2, #2
mov r3, #0
mov r4, r0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_3
mov r0, r4
mov r2, #14
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_4
mov r0, r4
mov r2, #1
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r0, [r4]
sub r0, r0, #24
ldr r0, [r0]
add r0, r0, r4
ldr r5, [r0, #240]
cmp r5, #0
beq .LBB0_5
@ BB#1: @ %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit
ldrb r0, [r5, #28]
cmp r0, #0
beq .LBB0_3
@ BB#2:
ldrb r0, [r5, #39]
b .LBB0_4
.LBB0_3:
mov r0, r5
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr r0, [r5]
mov r1, #10
ldr r2, [r0, #24]
mov r0, r5
mov lr, pc
mov pc, r2
.LBB0_4: @ %_ZNKSt5ctypeIcE5widenEc.exit
lsl r0, r0, #24
asr r1, r0, #24
mov r0, r4
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov r0, #0
pop {r4, r5, lr}
mov pc, lr
.LBB0_5:
bl _ZSt16__throw_bad_castv
.align 2
@ BB#6:
然而,老实说,这毫无意义,因为 I/O 无论如何都是瓶颈。我只是想证明这并不快,因为它是“类型安全”的。大多数 C 实现都使用计算的 goto 实现格式,因此即使编译器不知道,也尽可能快(并不是说它们不是 - 某些编译器可以在某些情况下进行优化 - 以 结尾的常量字符串通常优化为 )。iostream
printf
printf
printf
printf
\n
puts
遗产
我不知道你为什么要继承,但我不在乎。这也是可能的。ostream
FILE
class MyFile : public FILE {}
类型安全
诚然,可变长度参数列表没有安全性,但这并不重要,因为如果您启用警告,流行的 C 编译器可以检测到格式字符串的问题。事实上,Clang 可以在不启用警告的情况下做到这一点。printf
$ cat safety.c
#include <stdio.h>
int main(void) {
printf("String: %s\n", 42);
return 0;
}
$ clang safety.c
safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("String: %s\n", 42);
~~ ^~
%d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main’:
safety.c:4:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("String: %s\n", 42);
^
评论
std::sort
qsort
printf
是一个函数,而是一个变量。cout
评论
printf
是一个函数,但是一个函数调用 =)printf()
这里没有提到的两点我认为很重要:
1) 如果您尚未使用 STL,请携带大量行李。它向目标文件添加的代码量是 的两倍多。对于 也是如此,这也是我倾向于使用自己的字符串库的主要原因。cout
printf
string
2)使用过载的运算符,我觉得这很不幸。如果您还将运算符用于其预期目的(左移),这可能会增加混淆。我个人不喜欢为了与预期用途相切的目的而使运算符过载。cout
<<
<<
底线:如果我已经在使用 STL,我将使用 (和 )。否则,我倾向于避免它。cout
string
我想指出的是,如果你想在C++中使用线程,如果你使用,你可以得到一些有趣的结果。cout
请考虑以下代码:
#include <string>
#include <iostream>
#include <thread>
using namespace std;
void task(int taskNum, string msg) {
for (int i = 0; i < 5; ++i) {
cout << "#" << taskNum << ": " << msg << endl;
}
}
int main() {
thread t1(task, 1, "AAA");
thread t2(task, 2, "BBB");
t1.join();
t2.join();
return 0;
}
// g++ ./thread.cpp -o thread.out -ansi -pedantic -pthread -std=c++0x
现在,输出全部被打乱了。它也可以产生不同的结果,请尝试执行几次:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
您可以使用 to get it right,也可以使用 .printf
mutex
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
玩得愉快!
评论
thread
xyz
ABC
ABC
ABABAB
cout
"ABC"
"xyz"
AAA
BBB
cout
使事情交错,因为正如其他答案所指出的,不会作为单个调用运行,而是在一连串调用中运行,因此它们最终会交错运行。但与@Apollo提到的不同的是,它永远不会交错,并且会在一次调用中打印。但它可以打印类似 .cout
A
B
msg
#2: AAABBB
-std=c++0x
我不是程序员,但我做过人因工程师。我觉得编程语言应该易于学习、理解和使用,这就要求它有一个简单而一致的语言结构。尽管所有语言都是符号性的,因此其核心是任意的,但还是有约定俗成的,遵循这些约定使语言更容易学习和使用。
C++和其他语言中有大量的函数被写成函数(参数),这种语法最初用于前计算机时代数学中的函数关系。 遵循此语法,如果 C++ 的作者想要创建任何逻辑上不同的方法来读取和写入文件,他们可以简单地使用类似的语法创建不同的函数。printf()
在Python中,我们当然可以使用相当标准的语法进行打印,即变量名称.print,因为变量是对象,但在C++中它们不是。object.method
我不喜欢 cout 语法,因为 << 运算符不遵循任何规则。它是一种方法或函数,即它接受一个参数并对其执行某些操作。然而,它被写得好像是一个数学比较运算符。从人为因素的角度来看,这是一种糟糕的方法。
评论
TL的;DR:在信任网上随机评论之前,请务必对生成的机器代码大小、性能、可读性和编码时间进行自己的研究,包括这个评论。
我不是专家。我碰巧听到两位同事谈论我们应该如何避免在嵌入式系统中使用C++,因为性能问题。好吧,有趣的是,我根据真实的项目任务做了一个基准测试。
在上述任务中,我们必须将一些配置写入RAM。像这样:
咖啡=热
糖=无
牛奶=乳房
mac=AA:BB:CC:DD:EE:FF
这是我的基准测试程序(是的,我知道 OP 询问的是 printf(),而不是 fprintf()。尝试捕捉本质,顺便说一句,OP 的链接无论如何都指向 fprintf()。
C程序:
char coffee[10], sugar[10], milk[10];
unsigned char mac[6];
/* Initialize those things here. */
FILE * f = fopen("a.txt", "wt");
fprintf(f, "coffee=%s\nsugar=%s\nmilk=%s\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n", coffee, sugar, milk, mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
fclose(f);
C++程序:
//Everything else is identical except:
std::ofstream f("a.txt", std::ios::out);
f << "coffee=" << coffee << "\n";
f << "sugar=" << sugar << "\n";
f << "milk=" << milk << "\n";
f << "mac=" << (int)mac[0] << ":"
<< (int)mac[1] << ":"
<< (int)mac[2] << ":"
<< (int)mac[3] << ":"
<< (int)mac[4] << ":"
<< (int)mac[5] << endl;
f.close();
在我把它们都循环 100,000 次之前,我尽了最大努力打磨它们。结果如下:
C程序:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
C++程序:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
对象文件大小:
C - 2,092 bytes
C++ - 3,272 bytes
结论:在我非常具体的平台上,使用非常具体的处理器,运行非常具体版本的Linux内核,运行一个用非常具体版本的GCC编译的程序,为了完成一个非常具体的任务,我会说C++方法更合适,因为它运行速度明显更快,可读性更好。另一方面,在我看来,C 语言的占用空间很小,几乎没有任何意义,因为程序大小不是我们关心的问题。
Remeber,YMMV。
评论
sprintf()
write()
评论