为__attribute __支持自定义((格式)) [英] Custom support for __attribute__((format))
问题描述
GCC和锵两者都有支持,使对可变参数的功能,如的printf
编译时检查。这些编译器接受的语法如下:
Both GCC and Clang have a support to make compile-time checks on variable argument functions like printf
. These compilers accept syntax like:
extern void dprintf(int dlevel, const char *format, ...)
__attribute__((format(printf, 2, 3))); /* 2=format 3=params */
在OSX中,Cocoa框架也使用了这样的一个扩展的NSString
:
On OSX, the Cocoa framework also use an extension of this for NSString
:
#define NS_FORMAT_FUNCTION(F,A) __attribute__((format(__NSString__, F, A)))
在我们公司,我们有像一堆类即basestring
自定义的C ++框架从 BaseObject
所有派生。在即basestring
有几个可变参数的方法类似于的sprintf
,但也有一些扩展。例如,%S
预计类型的参数即basestring *
和% @
需要一个 BaseObject *
参数。
In our company, we have a custom C++ framework with a bunch of classes like BaseString
all deriving from BaseObject
. In BaseString
there are a few variable argument methods similar to sprintf
, but with some extensions. For example, "%S"
expects an argument of type BaseString*
, and "%@"
expects a BaseObject*
argument.
我想执行的在我们的项目参数的编译时检查,但由于扩展, __属性__((格式(printf的)))
给很多假阳性警告。
I would like to perform a compile-time check of the arguments in our projects, but because of the extensions, __attribute__((format(printf)))
give lots of false positive warnings.
有没有一种方法来定制 __ __属性的支持((格式))
两个编译器中的一个?如果需要修补程序编译器源代码,它是可行的在一个合理的时间?另外,是否有其他的皮棉的喜欢,可以执行检查工具?
Is there a way to customize the support of __attribute__((format))
for one of the two compilers ? If this requires a patch to the compiler source, is it doable in a reasonable amount of time ? Alternatively, are there other lint like tools that could perform the check ?
推荐答案
问了这个问题,一年半后,我想出了一个完全不同的方法来解决真正的问题:有什么办法静态检查类型的自定义可变参数的格式化报表?的
One year and a half after having asked this question, I came out with a totally different approach to solve the real problem: Is there any way to statically check the types of custom variadic formatting statements?
有关完整,因为它可以帮助其他人,这里是解决方案,我终于实现。它拥有超过原来的问题有两个好处:
For completeness and because it can help other people, here is the solution I have finally implemented. It has two advantages over the original question:
- 比较简单:在不到一天的时间来实现;
- 编译器独立:可以检查C ++ code任何平台(Windows,Android的,OSX,...)上
一个Perl脚本解析源$ C $ C,认定该格式字符串和德codeS里面他们百分之修饰。然后,将全部的论点为模板的身份函数的调用 CheckFormat<>
。例如:
A Perl script parses the source code, finds the formatting strings and decodes the percent modifiers inside them. It then wraps all arguments with a call to a template identity function CheckFormat<>
. Example:
str->appendFormat("%hhu items (%.2f %%) from %S processed",
nbItems,
nbItems * 100. / totalItems,
subject);
变成了:
str->appendFormat("%hhu items (%.2f %%) from %S processed",
CheckFormat<CFL::u, CFM::hh>(nbItems ),
CheckFormat<CFL::f, CFM::_>(nbItems * 100. / totalItems ),
CheckFormat<CFL::S, CFM::_, const BaseString*>(subject ));
该枚举 CFL
, CFM
和模板函数 CheckFormat
必须在这样的公共头文件中定义(这是一个提取物,大约有24重载)。
The enumerations CFL
, CFM
and the template function CheckFormat
must be defined in a common header file like this (this is an extract, there are around 24 overloads).
enum class CFL
{
c, d, i=d, star=i, u, o=u, x=u, X=u, f, F=f, e=f, E=f, g=f, G=f, p, s, S, P=S, at
};
enum class CFM
{
hh, h, l, z, ll, L=ll, _
};
template<CFL letter, CFM modifier, typename T> inline T CheckFormat(T value) { CFL test= value; (void)test; return value; }
template<> inline const BaseString* CheckFormat<CFL::S, CFM::_, const BaseString*>(const BaseString* value) { return value; }
template<> inline const BaseObject* CheckFormat<CFL::at, CFM::_, const BaseObject*>(const BaseObject* value) { return value; }
template<> inline const char* CheckFormat<CFL::s, CFM::_, const char*>(const char* value) { return value; }
template<> inline const void* CheckFormat<CFL::p, CFM::_, const void*>(const void* value) { return value; }
template<> inline char CheckFormat<CFL::c, CFM::_, char>(char value) { return value; }
template<> inline double CheckFormat<CFL::f, CFM::_, double>(double value) { return value; }
template<> inline float CheckFormat<CFL::f, CFM::_, float>(float value) { return value; }
template<> inline int CheckFormat<CFL::d, CFM::_, int>(int value) { return value; }
...
具有编译错误后,很容易用常规的前pression恢复原来的形式 CheckFormat&LT; [^&LT;] *&GT; \\(?(*)\\)
其捕获取代。
这篇关于为__attribute __支持自定义((格式))的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!