mk1*_*k12 7 c string compiler-warnings string-literals
我正在编写的小C库中有一个错误报告功能.我想提供errorf
除普通error
函数之外的函数,以便轻松地在错误消息中嵌入信息.
/*
* Prints a formatted error message. Use it as you would use 'printf'. See the
* 'sio_error' function.
*/
void sio_errorf(const char *format, ...) {
// Print the error prefix
if (g_input == STDIN) fputs("error: ", stderr);
else fprintf(stderr, "%s: ", g_progname);
// Pass on the varargs on to 'vfprintf'.
va_list arglist;
va_start(arglist, format);
// This may produce the following warning -- ignore it:
// warning: format string is not a string literal
vfprintf(stderr, format, arglist);
va_end(arglist);
fputc('\n', stderr);
}
Run Code Online (Sandbox Code Playgroud)
问题是,我收到此警告(使用-Weverything
开关编译clang 4.0 ):
警告:格式字符串不是字符串文字
我理解为什么这样做会很糟糕.有什么方法可以摆脱这个警告吗?我可以以某种方式强制该format
参数sio_errorf
是一个字符串文字,以便编译器知道它总是会,并且我只是传递它?
我知道我可以使用-Wno-format-nonliteral
,但只有当其他人也要手动编译它时,他们才会这样做.我宁愿在源代码中隐藏警告.
理想情况下,如果我传递给的字符串sio_errorf
实际上不是文字,我仍然会收到警告,但我不确定这是否可行.
jus*_*tin 11
如果您正在使用GCC或其亲属,请尝试声明中的属性:
void sio_errorf(const char *format, ...) __attribute__((format(printf, 1, 2)));
Run Code Online (Sandbox Code Playgroud)
要将属性添加到定义,可以使用以下命令:
__attribute__((format(printf, 1, 2)))
static void sio_errorf(const char *format, ...) {
....
Run Code Online (Sandbox Code Playgroud)
pax*_*blo 10
许多编译器允许您以这种或那种方式设置警告级别.例如,gcc允许-W
在调用编译器时通过命令行上的标志进行控制.
希望这是你正在使用的编译器,因为这样的程序:
#include <stdio.h>
int main (void) {
char *s = "xyzzy\n";
printf (s);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
生成您描述的确切消息(假设您已使用-Wformat
和启用了警告-Wformat-nonliteral
).
您要查找的特定命令行参数是:
-Wno-format-nonliteral
Run Code Online (Sandbox Code Playgroud)
这将防止有关在这些功能中使用非文字字符串的投诉.
但是,您可能正在寻找更细粒度的内容,因此它还允许您使用编译指示在代码中动态指定某些诊断消息的处置:
#include <stdio.h>
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
int main (void) {
char *s = "xyzzy\n";
printf (s);
return 0;
}
#pragma GCC diagnostic warning "-Wformat-nonliteral"
Run Code Online (Sandbox Code Playgroud)
如果你用它编译-Wformat -Wformat-nonliteral
,你将看不到警告,因为你告诉gcc忽略该main
函数的特定警告.
gcc的后续版本比我运行的版本具有以下选项:
#pragma GCC diagnostic push
#pragma GCC diagnostic pop
Run Code Online (Sandbox Code Playgroud)
这将推动和弹出诊断的状态.这解决了上面代码中的问题,您可能将该警告配置为错误 - 我的第二个pragma会将其更改为警告.
push/pop的使用将允许恢复其原始处置,例如:
#include <stdio.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
int main (void) {
char *s = "xyzzy\n";
printf (s);
return 0;
}
#pragma GCC diagnostic pop
Run Code Online (Sandbox Code Playgroud)