在 C++ 代码中禁用 C 字符串格式化方法
10.6.9 ID_forbidCStringFormat
C 字符串格式化方法的主要问题有:
- 需要手工维护参数与格式化占位符的对应关系
- 在编译期难以保证安全性,增加测试成本
- 与 C++ 的强类型理念不符,不在 C++ 标准之内
- 只接受基本类型的参数,不利于数据的对象化管理
故在 C++ 代码中禁用下列函数:
printf、fprintf、sprintf、snprintf、
wprintf、fwprintf、swprintf、
vprintf、vfprintf、vsprintf、vsnprintf、
vwprintf、vfwprintf、vswprintf
示例:
typedef int32_t mytype;
struct T {
mytype a;
};
void foo(const T* p) {
printf("%d", p->a); // Non-compliant, unportable
}
在 C 字符串格式化方法中,不同类型的参数依赖不同的格式化占位符,参数的类型与个数必须和占位符严格对应,否则就会导致未定义的行为,当参数较多时极易出错,单纯地要求开发者小心谨慎是不可靠的,改用更安全的方法才是明智的选择。
在 C++ 代码中利用标准流可避免这些问题,而且 C++ 标准流具备可扩展性,符合面向对象的编程理念:
std::ostream& operator << (std::ostream& os, const T& t) {
return os << t.a;
}
void foo(const T* p) {
std::cout << *p; // Compliant, safe and brief
}
当参数较多时,标准流的方式在形态上可能较为“松散”,在可读性上可能不如 printf 函数,而且重载 <<、>> 运算符的方式也会产生同步问题和额外的性能开销,对此 C++20 的“std::format”提供了更多的格式化方法。也可参见 ID_forbidVariadicFunction 的示例,用“模板参数包”等更安全的方法实现 printf 函数的功能。
相关
依据
ISO/IEC 9899:1999 7.19.6.1(2)-undefined
ISO/IEC 9899:1999 7.19.6.1(9)-undefined
ISO/IEC 9899:2011 7.21.6.1(2)-undefined
ISO/IEC 9899:2011 7.21.6.1(9)-undefined