Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
365 views
in Technique[技术] by (71.8m points)

c++ - How to use GCC's printf format attribute with C++11 variadic templates?

I have a C++ class that is the frontend for a logging system. Its logging function is implemented using C++11's variadic templates:

template <typename... Args>
void Frontend::log(const char *fmt, Args&&... args) {
  backend->true_log(fmt, std::forward<Args>(args)...);
}

Each logging backend implements its own version of true_log, that, among other things, uses the forwarded parameters to call vsnprintf. E.g.:

void Backend::true_log(const char *fmt, ...) {
  // other stuff..
  va_list ap;
  va_start(ap, fmt);
  vsnprintf(buffer, buffer_length, fmt, ap);
  va_end(ap);
  // other stuff..
}

Everything works great, and I am happy.

Now, I want to add a static check on the log() parameters: specifically, I would like to use GCC's printf format attribute.

I started by tagging the log() function with __attribute__ ((format (printf, 2, 3))) (as this is the first "hidden" parameter, I need to shift parameter indices by one). This does not work, because if fails with a compilation error:

error: args to be formatted is not ‘...’

Then, I tried to add the same attribute to the true_log() function. It compiles, but no error checking is actually performed: I tried to pass to log() some invalid format/variable combinations, and no warning was issued. Maybe this kind of check is "too late", or, in other words, the information about the variable has been lost in the chain of calls?

As a last resort, if I annotated log() with __attribute__ ((format (printf, 2, 0))), I would receive warnings about wrong format strings, but no diagnostic would be issued for invalid format/variable combinations.

Summarizing the problem: how can I have full format checking from GCC if I use C++11's variadic templates?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I don't believe you can. I bet that GCC only verifies the format string if it's a literal. This is why putting the format attribute on true_log doesn't work - that function is called with what looks (syntactically) like a runtime-determined string. Putting it on log directly would circumvent that, but would require format attributes to support variadic template, which you proved it doesn't.

I suggest that you look at more C++-ish ways to do formatted output. There is, for example, boost::format which works kind of like printf, but dynamically verifies that the number and types of the parameters types match the format string. It doesn't use variadic templates, though, but instead consumes parameters fed to it (via operator %) one-by-one.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...