我想编写一个类似printf的例程,而不是功能上的,但是我希望例程能够像printf一样编译检查特性。
例如,如果我有:
{
int i;
std::string s;
printf("%d %d",i);
printf("%d",s.c_str());
}
编译器抱怨如下:
1 cc1plus: warnings being treated as errors
2 In function 'int main()':
3 Line 8: warning: too few arguments for format
4 Line 9: warning: format '%d' expects type 'int', but argument 2 has type 'const char*'
编译器对待的printf和co特殊函数是不同的,或者是否有一些技巧可以让它在任何用户定义的函数上工作?我感兴趣的具体编译器是gcc和msvc
答案 0 :(得分:18)
不同的编译器可能会以不同方式实现此功能。在GCC中,它通过具有__attribute__
属性的format
说明符实现(阅读它here)。编译器执行检查的原因只是在GCC提供的标准头文件中,printf
函数声明为__attribute__((format(printf, 1, 2)))
以完全相同的方式,您可以使用format
属性将相同的格式检查功能扩展到您自己的可变参数函数,这些函数使用与printf
相同的格式说明符。
只有在您使用的参数传递约定和格式说明符与标准printf
和scanf
函数使用的参数相同时,才会执行此操作。检查被硬编码到编译器中。如果您对可变参数传递使用不同的约定,编译器将无法帮助您检查它。
答案 1 :(得分:5)
此行为高度依赖于编译器。我相信gcc provides an interface for type checking variadic functions。
答案 2 :(得分:2)
printf()
和朋友并不特别,因为他们接受可变数量的参数:用户定义的函数也可以接受可变数量的参数。它们很特殊,因为它们的行为是由标准定义的,因此编译器知道格式字符串与传递给函数的参数之间的相关性。
实际上,编译器知道在调用函数时传递了多少个参数,因此它解析格式字符串并将参数的预期数量和类型与实际传递给函数的参数进行比较,并在发出警告时发出警告他们不匹配。
如果您使用的是C ++,我会避免编写自己的可变参数函数;在大多数项目中使用它们的理由很少。例如,如果要进行格式化,请使用流或类似Boost Format的库。使用可变参数函数可以解决的任何问题都可以使用非可变函数来解决,并且几乎在所有情况下结果都更优雅,惯用且类型安全。
答案 3 :(得分:1)
实际上printf
根本没有任何固有的编译时安全性。事实上,一些更新的编译器已经实现了特殊检查,因为它们确切地知道格式字符串在附加参数方面的含义。当您使用...
作为参数时,您说您想接受任意参数并承担确保它们正确的全部责任。编译器无法检查它们的计数/类型安全性。
不要试图让编译器以这种方式帮助您,而是尝试使用标准流使用的方法:使用(可能是模板)函数或运算符返回对this
的引用以允许链接。然后,当参数与预期/支持的参数不匹配时,编译器将能够立即告诉您。
答案 4 :(得分:0)
前段时间有人向增强组发布了一个mpl :: string。我想它实际上可能已进入图书馆。如果是这种情况,你可以通过提供模板字符串作为模板参数(mpl :: string)然后使用一些非常深刻的元编程技巧来解析其中的格式化位来实现这样的事情。然后,您将使用此信息选择具有适当参数计数和类型的实现。
不,我不打算为你做这件事:P这将非常困难。但是,我相信它是可能的。