我对C中的属性格式说明符感到困惑。编译某些代码时遇到了警告。这是警告:
警告:格式[-Wformat-extra-args]
的参数太多以下是示例代码:
#include <stdio.h>
void test (int a, int b, const char* ax, const char* bx)__attribute__((format (printf, 3, 0)));
int main()
{
char * a = "abc";
char* b = "cde";
test(1,2,NULL,NULL); /*produces warning*/
test(1,2,a,NULL); /* does not produce warning */
}
void test(int a, int b, const char* ax, const char* bx)
{
printf("hello");
}
这是输出:
gcc -o asn.o test.c
test.c: In function ‘main’:
test.c:7:5: warning: too many arguments for format [-Wformat-extra-args]
test(1,2,NULL,NULL); /*produces warning*/
^~~~
只要满足以下条件(基于实验),就会产生警告:
以下代码似乎工作正常,这使我相信NULL是一个有效的字符串,因为它只检查一致性:
#include <stdio.h>
void test (int a, int b, const char* ax)__attribute__((format (printf, 3, 0)));
int main()
{
char * a = "abc";
char* b = "cde";
test(1,2,NULL);
test(1,2,a);
}
void test(int a, int b, const char* ax)
{
printf("hello");
}
有人可以向我解释这种行为吗?是否与属性格式说明符中的NULL或零有关?我正在使用gcc 7.2.0
编辑:
讨论中的更多信息。这里的问题是这不是一个可变函数,因此第三个参数传递为零。文档提到了这个
对于无法检查参数的函数(例如vprintf),请将第三个参数指定为零。
由于NULL是一个“一致”的字符串,我认为它不应该发出警告。同样重申这不是我的代码,而是来自一个着名的图书馆。
编辑2:
尝试了一些我遇到的使用类似签名的vsnprintf的东西。将NULL传递给格式字符串会导致三个警告
warning: null argument where non-null required (argument 3) [-Wnonnull]
vsnprintf (buffer,256,NULL, args);
^~~~~~~~~
testvsn.c:10:31: warning: too many arguments for format [-Wformat-extra-args]
vsnprintf (buffer,256,NULL, args);
^~~~
testvsn.c:10:3: warning: null format string [-Wformat-truncation=]
vsnprintf (buffer,256,NULL, args);
此时,我认为作为字符串传递的NULL只是未定义的行为或使用上面定义的函数不应该允许NULL字符串。如果有人有具体的答案,将会感激。
答案 0 :(得分:2)
对于printf
系列函数,NULL
不是有效的格式字符串。它会导致未定义的行为将NULL
作为格式字符串传递给标准库函数。
您发布的证据表明,gcc似乎并不支持您所希望的行为,即&#34;只有在参数为非NULL&#34;时才进行格式检查。
也许你可以提交错误报告,&#34;格式&#34;太多的参数;消息肯定是胡说八道。我猜它由于vprintf
的最后一个参数而假定0
模式,但由于实际上某个地方没有va_list
参数而感到困惑。
请注意,使用格式字符串的变量(即a
)意味着无论如何都无法检查字符串。它只检查格式字符串是字符串文字的情况;它不会尝试进行任何静态分析来跟踪变量的来源。您可以通过char *a = "%y"; test(1,2,a,NULL);
与test(1,2,"%y",NULL);
进行测试。
答案 1 :(得分:-2)
如果我删除了__attribute__
,则使用GCC 7.2.1警告消失。如果我将其留在-Wformat -Wformat-extra-args
,它就会停留。
您指定test
在位置3中采用格式字符串,然后再获取零个参数。这当然与你的功能完全矛盾。
printf
属性指令是GCC如何为 varargs 类型函数引发警告,您需要验证已传入的特定数量的参数,否则必须在运行时执行此操作。这不是你正在做的事情,所以你不应该使用该指令。
每当你遇到像这样不熟悉的东西时,需要花时间read the documentation以便在盲目使用之前更好地理解它们的目的。
简短回答:请勿在没有理由的情况下使用__attribute__
。