为什么gcc -Wall会警告零长度格式字符串?

31

我在网上搜寻了一些关于这个问题的信息,但并没有找到什么满意的答案。这个函数调用有特殊的行为吗?

sprintf(someString, "");

这是为什么在使用gcc和-Wall选项时会出现警告的解释?我只找到了C标准允许使用零长度格式字符串的说明。

我尝试了以下示例:

#include <stdio.h>

int main()
{
    char str[2] = {'a', 'a'};
    sprintf(str, "");
    printf("\'%c\'\'%c\'\n", str[0], str[1]);
    return 0;
}

这将打印出

'''a'

这正是我期望看到的,那么为什么会出现警告呢?


7
sprintf(str, "%s", ""); 不会让编译器报错。 - Nehal J Wani
4个回答

30
GCC发出警告通常与该语句是否合法无关,而与GCC开发人员是否认为它是一个可能表明您的意思与您所写的不同或者仅仅是糟糕风格的指示有关。以下是一些例子:
  • if (x = 0) — 您几乎肯定是想写成 if (x == 0)
  • printf(str) — 您几乎肯定是想要写成 fputs(str, stdout)printf("%s", str);按照原样编写的代码非常危险。
  • if (foo == bar & MASK) — 您几乎肯定是想要写成 if (foo == (bar & MASK))

等等。

在您的情况下,我认为GCC质疑您为什么要调用sprintf(String, "")来实现类似于String[0]=0;的操作(后者更短、更快、更清晰)。


2
我同意这样做会更好,只是我不知道是否有更多的原因来考虑它作为一个警告。我肯定不是权威,但我认为这种对合理编程的特定违规行为不应该被视为值得警告。 - SirGuy
3
我同意,但 GCC 的警告信息中有更令人烦恼的事情。这只是较小的问题。更大的问题是会对未使用的函数参数发出警告,当你使用必须符合特定签名的函数指针时,这是不可避免的。 - R.. GitHub STOP HELPING ICE
1
@YSC:那不是C语言。 - R.. GitHub STOP HELPING ICE
1
如果他们担心效率问题,他们可以只生成String[0]=0;而不是报告可疑的警告。我认为sprintf(String, "")更清晰,因为它更好地表达了一个“使字符串为空”的想法,而String[0]=0;仅表示“将字符串的第一个字节设置为零”。 - anton_rh
3
虽然在使用字面意义上的 printfsprintf 时警告很有用,但不幸的是,相同的警告也适用于任何使用“类似 printf”的属性的用户定义函数。这样的用户定义函数可能会产生其他效果(例如打印前缀或终止),即使字符串为空时也很有用。 - Kerrek SB
显示剩余3条评论

9
你收到这个警告是因为gcc知道sprintf()的第二个参数应该是一个非空字符串,通常应该包含各种格式规范——在你的代码中,一个功能上等效且“更合法”的调用方式是sprintf(str, "%s", "")。此外,几乎总会有一个到N个额外的参数,足以满足格式规范。在这里使用它时,你将其用作一种strcpy(),虽然从技术上讲是有效的,但这是一种非常奇怪的使用标准库的方式。

4

这只是GCC发出的一个警告。如果你希望在应用程序的某个部分中抑制它,可以执行以下操作:

#pragma GCC diagnostic ignored "-Wformat-zero-length"
int main()
{
     // code that produces a warning
}
#pragma GCC diagnostic warning "-Wformat-zero-length"

3
我知道我可以去除它,我想知道为什么一开始会有它。 - SirGuy
10
我认为这只是一个毫无意义且有害的警告。它可能对代码造成影响,特别是在格式字符串长度为零或受预处理器宏定义/值控制时,而这样的代码看起来是完全合理的。 - R.. GitHub STOP HELPING ICE
3
这段话的意思是:“这不会造成伤害。它只是告诉你有关于你的代码存在问题的地方,你可能犯了错误。虽然sprintf(str,"");是合法的,但这是一个比较绕弯子的方法,用来创建一个长度为零的字符串,这可能表明你的代码存在逻辑错误。这并不被禁止,只是引起你的注意。” - Phil Perry
4
@Phil,这是有害的,因为误报会使真正的警告更难被识别。大多数/全部-Wall都是你想要修复的合法问题,所以这会对此造成伤害。 - Conrad Meyer
1
这个警告使得在 -Werror 代码中调用一个公开的 __attribute__((format(printf(...)))) 库设置函数来将未公开的字符串缓冲区设置为空字符串变得困难(例如 User_details_set(&user, "");)。 - yyny

-1

-Wall可以合法地与-Wno-format-zero-length结合使用,当需要预先消除散布在代码中的一些#define字符串值时,非常有用。

-Wformat

选项-Wformat等同于-Wformat=1-Wno-format等同于-Wformat=0。由于-Wformat还检查多个函数的空格式参数,因此-Wformat也隐含了-Wnonnull

可以通过选项-Wno-format-contains-nul-Wno-format-extra-args-Wno-format-zero-length来禁用此级别的格式检查的某些方面。-Wall会启用-Wformat

这里是来源


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接