cout如何比printf()更安全
How cout is more typesafe than printf()
我在很多地方读过这篇文章,但不理解。为什么说cout比printf()更安全。只是因为它不需要写%d %c %f
,或者它有一些更深的含义。
提前谢谢。
这就是为什么:
printf("%sn", 42); // this will clobber the stream
这将导致缓冲区溢出——编译器通常无法检查printf
的第一个参数中的格式字符串是否与后续参数的类型相对应。在上述情况下,它可以这样做,因为字符串是硬编码的,一些编译器也会这样做。1但通常情况下,格式字符串可能在运行时确定,因此编译器无法检查其正确性。
1但是这些检查对于printf
是特殊情况。如果您使用与printf
相同的签名编写自己的myprintf
函数,则将无法检查类型安全性,因为签名使用省略号...
,该省略号会删除函数内的所有类型信息。
printf
族函数是变元函数,因为它们都使用省略号...
,这意味着就...
而言,任何类型的参数都可以传递给函数。编译器没有限制,因为参数的类型没有要求。编译器不能强制执行任何类型安全规则,因为省略号...
允许ALL类型。函数使用格式字符串来假设参数类型(即使存在不匹配!!)。格式字符串在运行时读取和解释,此时,如果由于代码已编译而出现不匹配,编译器将无法执行任何操作。因此,在这种情况下,这不是类型安全的所谓类型安全,通常是指编译器能够通过对(未赋值的)表达式的类型强加规则来检查程序的类型一致性
请注意,如果存在不匹配(函数无法解决!),程序将进入未定义的行为区域,在该区域,程序的行为是不可预测的,理论上任何事情都可能发生。
您可以将相同的逻辑扩展到任何可变函数函数,如scanf
族。
-
类型系统用CCD_ 12而不是CCD_。康拉德的回答是一个例子,但有点像
printf("%ldn", 7);
也已损坏(假设系统中的
long
和int
大小不同)。它甚至可能与一个构建目标一起工作,而与另一个目标一起失败。尝试打印像size_t
这样的typedef也有同样的问题。一些编译器提供的诊断程序(在某种程度上)解决了这个问题,但这对第二种感觉没有帮助:
-
两个类型系统(格式化字符串中使用的运行时类型系统和代码中使用的编译时系统)都不能自动保持同步。例如,
printf
与模板的交互很差:template <typename T> void print(T t) { printf("%dn",t); }
你不能对所有类型的
T
都这样做-你能做的最好的是static_cast<int>(t)
,所以如果t不能转换为int,它将无法编译。比较template <typename T> void print(std::ostream& os, T t) { os << t << 'n'; }
其为具有CCD_ 21的任何CCD_。
通常,编译器不能检查printf中的参数,甚至不能检查参数计数,也不能检查它们是否适合字符串格式。它们被"优化"以完成这项工作,但这是一种特殊情况,可能会失败。示例:
printf("%s %dn", 1, "two", 3);
这将进行编译(除非优化的编译器检测到失败),并且在运行时,printf将第一个参数(1)视为字符串,第二个参数("2")视为整数。printf甚至不会注意到有第三个参数,如果没有足够的参数,也不会注意到!
使用cout,编译器必须选择特定的运算符<lt;对于您插入的每个变量。示例:
cout<<1<<"two"<<3<<endl;
编译器必须在调用相应的ostream&operator<<(int)
和ostream&operator<<(const char*)
(以及ostream&operator<<(ios&(*)(ios&))
)时更改此项。
cout也会更快,因为没有对格式字符串的运行时解释。
来自C++常见问题解答:
[15.1]为什么我应该使用
<iostream>
而不是传统的<cstdio>
[…]
更安全的类型:通过,编译器静态地知道要I/O的对象的类型。相反,使用"%"字段来动态地计算类型。
[…]
对于printf
,编译器无法检查第一个参数的格式脚本是否与其他参数的类型相对应一般来说,它是在运行时完成的
- 从不同线程使用int64的不同字节安全吗
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 虚拟决赛作为安全
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何将元素添加到数组的线程安全函数?
- C++中的线程安全删除
- 通过网络、跨平台传递std::变体是否安全
- 为什么在C的循环中使用printf的Rust代码不显示输出,而在C++的循环中显示std::cout
- 内联程序集printf将整数解释为地址
- 在std::thread中,joinable()然后join()线程安全吗
- 使用std::istream::peek()总是安全的吗
- 为什么mpfr_printf与十六进制浮点(%a转换说明符)的printf不同
- 从值小于256的uint16到uint8的Endian安全转换
- 在c++队列中使用pop和visit实现线程安全
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 全局变量 多读取器 一个写入器多线程安全?
- 是否有任何类型安全的、编译时检查的 printf 的实现
- cout如何比printf()更安全
- scanf、printf和boost::lexical_cast基本上不安全吗?