Nathan Fellman
Nathan Fellman

Reputation: 127428

How should I properly use __attribute__ ((format (printf, x, y))) inside a class method in C++?

I'm trying to define a class method for debug prints that will behave like printf:

inline void debug(const char* fmt, ...) __attribute__ ((format (printf, 1, 2)))

When I compile with -Wformat or -Wall, This complains about:

error: format string argument not a string type

I recalled that a class method declaration has an implicit this parameter, so I changed the locations of the parameters to 2, 3:

inline void debug(const char* fmt, ...) __attribute__ ((format (printf, 2, 3)))

and now it compiles, but it looks like the parameters are shifted, as if the this parameter were being treated as part of the argument list.

How can I tell the function that this isn't part of the string that I want to print?

Upvotes: 48

Views: 41097

Answers (4)

Gabriel Staples
Gabriel Staples

Reputation: 52489

@Chris Dodd is correct.

Use:

inline void debug(const char* fmt, ...) __attribute__ ((format (printf, 2, 3)));

Since debug() is a C++ class member function, the first argument to it is automatically implicitly the class's this argument. So, using (printf, 2, 3) says that 2 is the format string string-index, which means that the second argument (ie: the first argument after this) is the format string, and the 3 is the first-to-check argument, which means the 3rd arguments is the first value which gets substituted into the format string.

Here's the latest gcc documentation to back it up (thanks Foxit reader for letting me mark up PDFs on Linux). Pay special attention to the part marked in green in the image below.

Since non-static C++ methods have an implicit this argument, the arguments of such methods should be counted from two, not one, when giving values for string-index and first-to-check.

Source:

  1. https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Common-Function-Attributes.html#Common-Function-Attributes (see the section titled "format (archetype, string-index, first-to-check)").
  2. Latest documentation: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

Image (esp. see highlighting in green):

enter image description here

Upvotes: 6

sage
sage

Reputation: 5514

Treat static members the same as non-members. The discussion gave me the answer, but it's worth noting for others:

  • non-member functions work with 1,2
  • static member functions work with 1,2
  • non-static member functions treat 'this' as #1, so need 2,3

I found this because we have some processes that use log helpers like this and 1 out of 4 was requiring __attribute__ (( format( printf, 2, 3 ) )) with the other three working well with __attribute__ (( format(printf, 1, 2) )) - turned out it was non-static...

Upvotes: 6

Don Carr
Don Carr

Reputation: 331

Since it only works for gcc, it would be good to define it this way to avoid errors on other compilers.

#ifdef __GNUC__
          __attribute__ (( format( printf, 2, 3 ) ))
#endif

Upvotes: 3

Chris Dodd
Chris Dodd

Reputation: 126193

You've done it. this is argument 1, so by saying format(printf, 2, 3) you're telling the compiler that you're NOT printing this, you're printing argument 2 (fmt) with additional arguments past that.

Upvotes: 47

Related Questions