2

It is very common for any medium-to-large project to replace printf with a custom log function. Here is a minimal C++ example and its usage:

#include <stdio.h>
#include <stdarg.h>
#include <string>

void log_printf(const char* fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    vprintf(fmt, ap); // real code obviously does something fancier
    va_end(ap);
}

int main() {
    std::string x = "Hello";

    // correct code
    printf("String is %s\n", x.c_str());
    log_printf("String is %s\n", x.c_str());

    // incorrect code
    printf("String is %s\n", x); // bad line 1
    log_printf("String is %s\n", x); // bad line 2
}

The simple logger receives a variable amount of arguments and calls vprintf to output them to standard output. The lines under 'correct code' demonstrate correct usage of this logger. My question involves the 'bad' lines, where a string object is incorrectly passed instead of a pointer to the character buffer.

Under GCC 4.6 (tested under Linux) neither of the bad lines can compile, which is a good thing because I want to catch such incorrect usage. The error is:

error: cannot pass objects of non-trivially-copyable type ‘std::string {aka struct std::basic_string<char>}’ through ‘...’

However in GCC 5.1 it has apparently become possible to pass non-trivially-copyable objects, and the compilation succeeds. If I use -Wall then only 'bad line 1' raises a warning about an unexpected argument type, but 'bad line 2' with the log_printf compiles without issue in any case. Needless to say both lines produce garbage output.

I can catch 'bad line 1' with -Wall -Werror, but what about 'bad line 2'? How can I cause it to also generate a compilation error?

1 Answer 1

2

For your own functions you need to use a common function attribute call format:

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

void log_printf(const char* fmt, ...) {
    ...
}

Note that the attribute must be set on a function declaration, not the definition.

The first argument to the format attribute is the style, in this case printf (scanf is also possible, for functions that works like scanf), the second argument is the format string, and the third argument is where the ellipsis ... is. It will help GCC check the format strings like for the standard printf function.

This is a GCC extension, though some other compilers have adopted it to become GCC compatible, most notably the Intel C compiler ICC and Clang (the standard compiler used on OSX and some BSD variants). The Visual Studio compiler does not have this extension, and I know of no similar thing for Visual C++.

Sign up to request clarification or add additional context in comments.

1 Comment

@José You mean it doesn't show the warnings? Try it in a non-online compiler and you will see them. Neither that, nor Ideone seems to show warnings.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.