避免在printf的包装中发出警告

我正在编写的小C库中有一个错误报告function。 除了普通errorfunction之外,我还想提供一个errorf函数,以便轻松地在错误消息中嵌入信息。

 /* * 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); } 

问题是,我收到此警告(使用-Weverything开关使用clang 4.0进行编译):

警告:格式字符串不是字符串文字

我理解为什么这样做会很糟糕。 有什么方法可以摆脱这个警告吗? 我可以以某种方式强制format参数sio_errorf是一个字符串文字,以便编译器知道它总是会,并且我只是传递它?

我知道我可以使用-Wno-format-nonliteral ,但只有当其他人也要手动编译它时,他们才会这样做。 我宁愿在源代码中隐藏警告。

理想情况下,如果我传递给sio_errorf的字符串实际上不是文字,我仍然会收到警告,但我不确定这是否可行。

如果您正在使用GCC或其亲属,请尝试声明中的属性:

 void sio_errorf(const char *format, ...) __attribute__((format(printf, 1, 2))); 

要将属性添加到定义,可以使用以下命令:

 __attribute__((format(printf, 1, 2))) static void sio_errorf(const char *format, ...) { .... 

许多编译器允许您以这种或那种方式设置警告级别。 例如,gcc允许在调用编译器时通过命令行上的-W标志进行控制。

希望这是你正在使用的编译器,因为这样的程序:

 #include  int main (void) { char *s = "xyzzy\n"; printf (s); return 0; } 

生成您描述的确切消息(假设您已使用-Wformat-Wformat-nonliteral启用了警告)。

您要查找的特定命令行参数是:

 -Wno-format-nonliteral 

这将防止在这些function中使用非文字字符串的投诉。

但是,您可能正在寻找更细粒度的内容,因此它还允许您使用编译指示代码中动态指定某些诊断消息的处置:

 #include  #pragma GCC diagnostic ignored "-Wformat-nonliteral" int main (void) { char *s = "xyzzy\n"; printf (s); return 0; } #pragma GCC diagnostic warning "-Wformat-nonliteral" 

如果使用-Wformat -Wformat-nonliteral编译它, 则不会看到警告,因为您已告知gcc忽略main函数的特定警告。

gcc的后续版本比我运行的版本具有以下选项:

 #pragma GCC diagnostic push #pragma GCC diagnostic pop 

这将推动和弹出诊断的状态。 这解决了上面代码中的问题,您可能将该警告配置为错误 – 我的第二个编译指示会将其更改为警告。

推/弹的使用将允许恢复其原始处置,例如:

 #include  #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