C fprintf,错误:格式不是字符串文字且没有格式参数[-Werror=格式安全性

C fprintf,错误:格式不是字符串文字且没有格式参数[-Werror=格式安全性,c,linux,gcc,compiler-errors,C,Linux,Gcc,Compiler Errors,当我试图在Ubuntu上编译fprintf(stderr,用法)时,我遇到了以下错误: error: format not a string literal and no format arguments [-Werror=format-security 但当我在其他linux发行版(RedHat、Fedora、SUSE)上编译时,它已经编译成功了 有人有想法吗?你应该使用fputs(用法,标准); 如果不进行格式化,则无需使用fprintf。如果要使用fprintf,请使用fprintf(

当我试图在Ubuntu上编译
fprintf(stderr,用法)
时,我遇到了以下错误:

 error: format not a string literal and no format arguments [-Werror=format-security
但当我在其他linux发行版(RedHat、Fedora、SUSE)上编译时,它已经编译成功了

有人有想法吗?

你应该使用
fputs(用法,标准);

如果不进行格式化,则无需使用fprintf。如果要使用fprintf,请使用
fprintf(stderr,“%s”,用法);

Ubuntu上的包含
-Wformat-Wformat security
,这就是导致此错误的原因

该标志用于预防引入与安全相关的bug,想象一下 如果你以某种方式这样做,就会发生:

char *Usage = "Usage %s, [options] ... ";
...
fprintf(stderr, Usage);
这将与
fprintf(标准,“用法%s,[选项]…]”哪个是错误的

现在,
用法
字符串包含一个格式说明符,
%s
,但您没有将该参数提供给
fprintf
,从而导致未定义的行为,可能会使程序崩溃或允许其被利用。如果传递给fprintf的字符串来自用户输入,则这一点更为相关

但是如果您使用fprintf(stderr,“%s”,“用法%s,[选项]…]”没有这样的问题。二,<代码>%s
不会被解释为格式说明符。
gcc会对此发出警告,默认的Ubuntu编译器标志会使其成为编译器错误。

使用
fputs(用法)
fprintf(stderr,“%s”,用法)
。将消息字符串传递给
printf
-族函数的习惯用法是危险的,因为除非已知它不包含格式说明符,否则字符串中任何可能的格式说明符都将被解释并导致未定义的行为(因为它们没有对应的参数),这几乎总是会转化为安全漏洞。

使用只有两个参数的
fprintf()
是完全正确的。正如函数定义明确指出的,第二个之后的所有参数都是可选的

当第二个参数不包含format子句时,此警告实际上会变成一个错误,之所以引入GCC是因为错误地假设
fprintf()
的第二个参数始终包含format子句。关于这个假设,没有什么是正确的。这是一个有缺陷的决定,一个bug,在较新版本的GCC中得到了修复,它实际上检查了第二个参数,以确保在需要时提供适当数量和类型的附加参数

混合使用
fputs()
fprintf()
调用是在寻找bug。另外,这只会让代码更难看。只要您使用的是最新的、理智的GCC,那么在任何地方使用
fprintf()
都会更干净


这个故事的寓意很简单:永远不要修改好的代码来使坏的编译器高兴。

您尝试的编译器版本是什么,以及
用法是什么
你能给我们看看有问题的
printf
语句吗?不同的编译器选项。在Ubuntu上,您使用
-Werror=格式安全性
,而在其他版本上则不使用。我有一些变通方法,比如:fprintf(stderr,“%s”,Usage),或const char Usage[],GCC版本是:GCC(Ubuntu/Linaro 4.6.3-1ubuntu5)4.6.3您能解释一下您所指的GCC bug吗?上面提出的更改(例如,使用FPUT)并不能使编译器满意。当不需要复杂的格式化逻辑时,它们通过避免复杂的格式化逻辑来防止错误。对于文本,编译器会检查转换指令是否与参数匹配,从而消除许多错误。但是对于可变格式字符串,程序员是独立的,这可能会导致糟糕的结果。