14

这是一小段代码:

#include <stdio.h>
#include <stdarg.h>

void MyPrintf(char const* format, va_list args);
void MyVariadicPrintf(char const* format, ...);

void MyPrintf(char const* format, va_list args)
{
    vprintf(format, args);
}

void MyVariadicPrintf(char const* format, ...)
{
    va_list args;
    va_start(args, format);
    MyPrintf(format, args);
    va_end(args);
}

int main(int, char*)
{
    MyVariadicPrintf("%s" /* missing 2nd argument */);

    return 0;
}

我正在用 GCC 4.0 编译它,在 Mac OS X Leopard 上运行 Xcode。
-Wformat 和 -Wmissing-format-attribute 已启用。
此代码在第 9 行(调用vprintf)给出警告,表明MyPrintf可以使用“格式”属性:

函数可能是“printf”格式属性的候选者

所以我以这种方式添加属性(不确定这是否正确):

void MyPrintf(char const* format, va_list args) __attribute__((format(printf, 1, 0)));

之前的警告消失了,同样的警告现在出现在第 16 行(调用MyPrintf),表明MyVariadicPrintf可以使用 'format' 属性。
所以我以这种方式添加属性(很确定这次是正确的):

void MyVariadicPrintf(char const* format, ...) __attribute__((format(printf, 1, 2)));

现在我在第 22 行得到了预期的警告(调用MyVariadicPrintf):

格式参数太少

  1. 我做对了吗?
  2. 我注意到在MyPrintf声明时,如果我删除属性部分,我仍然会在第 22 行得到想要的警告。我还注意到,在这个属性部分中,将索引从 1 更改为 2 不会给出任何警告或错误。哪一个是正确的,这个函数的属性的目标是什么?
  3. 如果我添加以下函数MyVariadicPrintfT并调用它(专用于char),我将收到建议在此函数上使用“格式”属性的警告。我认为这是不可能的,因为format参数取决于模板类型。我对吗?

    template<typename Type>
    void MyVariadicPrintfT(Type const* format, ...)
    {
        va_list args;
        va_start(args, format);
        MyPrintf(format, args);
        va_end(args);
    }
    

最新的 gnu 文档可以在gnu.org找到。
警告选项在第 3.8 节中(查找“-Wmissing-format-attribute”)。
函数属性在第 6.30 节中(查找“格式(原型,字符串索引,首先检查)”)。

谢谢。

4

2 回答 2

11

该文档有您需要的答案。特别:

  1. 是的
  2. 您发布的是正确的(format(printf, 1, 0))。1 因为格式字符串是参数 1,0 因为没有要检查的可变参数。
于 2009-06-15T15:53:25.973 回答
4

查看gnu.org上的GCC 文档。至于最后一个问题,我猜这MyPrintf不是模板函数,唯一可用的定义char const*作为第一个参数,所以提出建议感觉很安全。

于 2009-06-15T15:47:13.047 回答