当前位置: 首页 > 知识库问答 >
问题:

属性格式说明符警告 。需要一些澄清

包丁雨
2023-03-14

我对c中的属性格式说明符感到困惑。我在编译一些代码时遇到了一个警告。以下是警告:

警告:格式的参数太多 [-W 格式-额外参数]

下面是一个示例代码:

#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*/
     ^~~~

只要满足以下条件(基于实验),就会发出警告:

    < li >要检查的格式为空。 < li >在属性格式说明符的第三个参数中传递了一个零 < li >格式不是函数中的最后一个参数。

以下代码似乎工作正常,这让我相信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字符串。如果有人能给出具体的答案,我将不胜感激。

共有2个答案

萧心远
2023-03-14

如果我删除__attribute__碎屑,则使用GCC 7.2.1时警告会消失。如果我把它留在 -W 格式 -W格式 -额外参数 中,它就会留下来。

您指定test在位置3接受格式字符串,然后接受零个附加参数。这当然与您的函数完全矛盾。

< code>printf属性指令是GCC为varargs类型函数发出警告的方式,在这种情况下,您需要验证是否已经传入了一定数量的参数,否则您必须在运行时执行这些操作。这不是你正在做的事情,所以你不应该使用那个指令。

每当你遇到像这样不熟悉的东西时,在盲目使用它们之前,花点时间阅读留档以更好地理解它们的目的。

简短的回答:不要无缘无故地使用__attribute__

岳曦
2023-03-14

对于printf系列函数,NULL不是有效的格式字符串。它会导致未定义的行为将NULL作为格式字符串传递给标准库函数。

你张贴的证据表明,gcc似乎不支持你所希望的行为,即“只做格式检查,如果参数非空”。

也许你可以提交一个错误报告,“格式参数太多”的消息肯定是无稽之谈。我猜它假设vprintf模式是由于0的最后一个参数,但它变得混乱,因为实际上没有va_list参数。

请注意,为格式字符串使用变量(即a)意味着无论如何都无法检查字符串。它只检查格式字符串是字符串文字的情况;它不会尝试进行任何静态分析来跟踪变量的来源。您可以通过执行char*a="%y"; test(1,2, a, NULL);test(1,2,"%y", NULL);来测试这一点。

 类似资料:
  • 现在,编辑器在使用注释方法的地方显示警告。然后显示使用的建议。当我接受它的更改时,它会将代码转换为此,警告消失。 使用有意义吗? 实现是 所以如果为空,我的代码仍然会崩溃。 我们应该对此进行空检查。 我认为比好,你说呢?如果是,则编辑器不应建议在此处使用。 因为在具有状态(如)的字段中使用要求NonNull是不安全的。我是否错过了的一些好处?

  • 当我尝试编译它时,我收到以下错误,不知道为什么…… 警告:格式“%x”需要类型为“unsigned int”的参数,但参数2的类型为“char *”[-w format =] 代码:

  • 本文向大家介绍Fortran 分配格式说明符,包括了Fortran 分配格式说明符的使用技巧和注意事项,需要的朋友参考一下 示例 在Fortran 95之前,可以将分配的格式用于输入或输出。考虑 该assign语句将语句标签分配给整数变量。以后将此整数变量用作print语句中的格式说明符。 在Fortran 95中删除了这种格式说明符分配。相反,更现代的代码可以使用其他形式的执行流控制 或字符变量

  • 说我想打印: 这是正确的。这: 或者这个: ? 事情是在其他地方,所以我遇到了这样的讨论: -即使ch变为无符号字符,代码的行为也不是由C标准定义的。这是因为无符号字符被提升为int(在普通的C实现中),所以int被传递给printf的说明符%u。但是,%u需要一个无符号int,所以类型不匹配,并且C标准没有定义该行为 -你的评论不正确。C11标准规定转换说明符必须与函数参数本身的类型相同,而不是

  • 设置一个应该在图像上放置广告的应用程序时,我在运行代码时遇到了这个WordPress错误,这是一个令人沮丧的星期试图修复这个问题。 我希望它能工作,但它给了我以下错误:警告:preg_replace_callback():需要参数2,' 如果有人能想出一个解决方案,那将是惊人的,非常感谢!

  • 我刚刚更新了PHP在我的服务器从PHP 5到PHP 7,我得到了这些警告: 警告:preg_replace_callback()[function.preg-replace-callback0]:要求参数2“chr(\1)”是有效的回调 警告:preg\u replace\u callback() 警告:preg_replace_callback()[function.preg-replace-c