2

Consider the following call:

NSString* localized = NSLocalizedString([NSString stringWithFormat:@"Hello %@", @"World"], @"");

What is wrong with it? I see nothing inherently wrong, yet the compiler/preprocessor complains that too many parameters were passed to it. On the other hand, the following two compile:

Explicit variable:

NSString* string = [NSString stringWithFormat:@"Hello %@", @"World"];
NSString* localized = NSLocalizedString(string, @"");

Wrap in brackets:

NSString* localized = NSLocalizedString(([NSString stringWithFormat:@"Hello %@", @"World"]), @"");

Looks like the preprocessor/compiler incorrectly parses the , character.

I am getting this in Xcode 7 beta 6, so it might be a new bug in the Clang toolchain.

Léo Natan
  • 56,823
  • 9
  • 150
  • 195
  • File a bug report with Apple. – rmaddy Aug 25 '15 at 14:32
  • @rmaddy I did, #22418824 – Léo Natan Aug 25 '15 at 14:33
  • 1
    BTW - shouldn't the 1st param to `NSLocalizedString` be a string literal? Remember, you use the command line tool `gestrings` to generated the localized strings file. This means it simply parses your source code files. It makes no sense to define your keys based on a runtime value. – rmaddy Aug 25 '15 at 14:42
  • Yes, the sense is not strong in the example above. I meant to have the format itself localized, but did it like that by mistake. Still, cool bug. `:-)` – Léo Natan Aug 25 '15 at 14:43
  • @rmaddy Strictly speaking, it's not true what you are saying. I could generate the strings files myself, and have all the possible dynamic values I want as strings. It *is* possible. – Léo Natan Aug 25 '15 at 14:44

1 Answers1

2

This isn't a bug, it is how the C pre-processor works. From the C Standard:

The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments.

So commas delimit macro arguments unless they are inside matching inner parentheses - this is your "wrap in brackets" variation works. C doesn't talk about matching brackets, [ & ], only parentheses, ( & ), so your first example has three macro arguments: [NSString stringWithFormat:@"Hello %@", @"World"] and @"". Preprocessing takes place before syntax analysis, so the fat that the first two arguments don't make syntactic sense in (Objective-)C doesn't matter.

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86
  • But this is a `.m` file that is being preprocessed. Should this preprocessor not be expanded to be familiar with Objective C syntax brackets just like it is familiar with C syntax brackets? – Léo Natan Aug 25 '15 at 16:28
  • 1
    @LeoNatan - Well that is a different question! ;-) Should it? Could it? Remember that macro expansion is defined to occur *before* syntax analysis, so while it could be done its not a simple as it may sound. You also need to make sure that such a change wouldn't break any C macro usages, remember Objective-C is a superset of C and all standard C should compile without error. – CRD Aug 25 '15 at 16:37
  • 2
    BTW The better fix for Apple would be to define `NSLocalizedString` as an inline function, this both avoids the problem you hit and gives more "normal" behaviour (each argument only evaluated once, etc.). – CRD Aug 25 '15 at 16:40
  • Agreed, best solution. – Léo Natan Aug 25 '15 at 16:41
  • @LeoNatan Objective-C is fully C compliant (accept of additional keywords), so the preprocessor, coming from C, should work exactly the same way it does in C. One could rely on the defined behavior in C, when writing Objective-C code. – Amin Negm-Awad Sep 03 '15 at 05:20
  • Yes, one shouldn't use "function style" macros: They look like functions and behave like word. – Amin Negm-Awad Sep 03 '15 at 05:22
  • @AminNegm-Awad Obviously not the case here. Objective C extends the syntax, but the preprocess has not been upgraded to support it. – Léo Natan Sep 03 '15 at 06:00
  • Yes, because this would be an nonconforming extension. If one knows the standard, he can rely on the defined behavior, *including in your case*. (You do not know, what one wants to do in the macro.) – Amin Negm-Awad Sep 03 '15 at 07:40