Avoid warning in wrapper around printf

巧了我就是萌 提交于 2019-11-28 03:53:50

问题


I have an error reporting functionality in my little C library I'm writing. I want to provide an errorf function in addition to the plain error function to allow embedding information in error messages easily.

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

The problem is, I get this warning (compiling with clang 4.0 with the -Weverything switch):

warning: format string is not a string literal

I understand why doing this would be bad. Is there any way I can get rid of this warning? Can I somehow enforce that the format argument sio_errorf be a string literal, so that the compiler knows that it always will be, and that I'm simply passing it on?

I know I can use -Wno-format-nonliteral, but only if other people are going to manually compile it too, they won't do that. I'd rather something in the source code that silences the warning.

Ideally I would still get the warning if the string I passed to sio_errorf actually isn't a literal, but I'm not sure if that's possible.


回答1:


If you're using GCC or one of its relatives, try an attribute on the declaration:

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

To add the attribute to a definition, you can use this:

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



回答2:


Many compilers will allow you to set warning levels in one way or another. For example, gcc allows the control via -W flags on the command line when invoking the compiler.

Hopefully that's the compiler you're using since a program like this:

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

generates the exact message you describe (assuming you've enabled the warnings with -Wformat and -Wformat-nonliteral).

The particular command line argument you would be looking for is:

-Wno-format-nonliteral

which will prevent complaints about the use of non-literal strings in those functions.

However, you may be looking for something more fine-grained so it also allows you to specify the disposition of certain diagnostic messages on the fly within your code with pragmas:

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

If you compile that with -Wformat -Wformat-nonliteral, you won't see the warning, because you've told gcc to ignore that particular warning for the main function.

Later versions of gcc than the one I run have the following options:

#pragma GCC diagnostic push
#pragma GCC diagnostic pop

which will push and pop the state of the diagnostics. This gets around the problems in my code above where you might configure that warning as an error - my second pragma would change it into a warning.

The use of push/pop would allow restoration to its original disposition with something like:

#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


来源:https://stackoverflow.com/questions/12171132/avoid-warning-in-wrapper-around-printf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!