[cfe-dev] Generating printf format specifiers

David Chisnall theraven at sucs.org
Sun Jan 24 06:16:07 CST 2010

On 24 Jan 2010, at 09:16, Jens Ayton wrote:

> On Jan 22, 2010, at 19:35, Dave Keck wrote:
>> I imagine __nsfmt__ would work similarly to __typeof__, but rather than substituting the type, the compiler would substitute the most natural printf format specifier for the given type. There would also be a standard-C __fmt__ that would generate constant C-strings rather than constant NSStrings.
> As a side note, it wouldn't actually be necessary to make this distinction if __fmt__() was semantically treated as a string literal, since you can concatenate C string literals to ObjC ones:
> @"Hello, " "World"
> @"Hello, " __fmt__(userName) "!"
> #define __nsfmt__(x) @__fmt__(x)

This works because, from the parser's point of view, an Objective-C string is an @ token followed by a C-string token.  In fact, you are not concatenating C strings with Objective-C strings at all.  The preprocessor is concatenating two C strings then the parser is constructing an Objective-C string from an @ and a C string.

I like the idea of __fmt__(), but it will be tricky to implement.  The string concatenation happens in the preprocessor, but the type information isn't available until much layer.  This is why you can't do things like #if sizeof(int) == 4 in preprocessor macros, even though everyone wants to.  With clang, in normal operation, the preprocessor isn't quite such a separate step as in a traditional C compiler (where it is an entirely separate program), so this might be possible.

If you're happy with adding incompatible language extensions, maybe you should consider, as an alternative, adding a new type specifier that's understood in format strings to functions marked with the printf attribute.  That way, you'd do something like this:

NSLog(@"Hello, %!! This is your user id: %!", username, userID);

The printf format string checker in clang already has code to see what the format string for the specified type should be, so you can just have it replace the ! with the correct value in the string.

Note that this has some problems, however.  If the argument is an int, for example, would you insert %x or %d?  This applies even with the original __fmt__() pseudo-macro idea.  There is not an injective mapping from types to format strings.  This is especially true if you consider modifiers.  With __fmt__(), I'm not sure how you would specify whether to show the sign, the precision, or the width, for example.  


-- Sent from my brain

More information about the cfe-dev mailing list