问题
Here is the full program. Can you figure out its console output?
#import <Foundation/Foundation.h>
#define kEnv YES
#if kEnv
#define x @"abc"
#else
#define x @"xyz"
#endif
#define kVersion true
#if kVersion
#define y @"abc"
#else
#define y @"xyz"
#endif
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"x: %@; y: %@", x, y);
NSLog(@"%@", kEnv ? @"abc" : @"cba");
NSLog(@"%@", kVersion ? @"abc" : @"cba");
}
return 0;
}
Before moving forward, you can copy & paste, run, and checkout the result yourself.
The output is:
x: xyz; y: abc
abc
abc
Can anyone explain the reason?
回答1:
YES
gets defined as __objc_yes
in <objc/objc.h>, and that is a compiler-level symbol, unknown to the preprocessor.
(/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/objc/objc.h on my machine.)
You can see the definition by doing
#define T(X) #X
#define S(X) T(X)
printf("YES is: \"%s\"\n", S(YES));
The C preprocessor is an interesting beast. :)
EDIT: Why does
#if __objc_yes
behave as if __objc_yes
was false? Because __objc_yes
is completely unknown to the preprocessor; it is known only to the compiler. This is from the manual to the GNU preprocessor, but I believe it reflects the standard, about what the expression after #if
can contain:
[...] Identifiers that are not macros, which are all considered to be the number zero. [...]
回答2:
If you add
#define YES 1
at the beginning you'd get the output you expect. The reason is that YES
definition is probably more complex than the way given here and that messes up the preprocessor. You can test that by e.g. changing your test to
#if YES
(and removing my definition of YES) and you'd get the same result as you did earlier. This just shows that, however YES
is defined, it does not trigger the
#if YES
test.
PS
I think if you want to use constants e.g.
#if XXX
or
#if XXX > 5
you need to define XXX
as a numerical value otherwise the preprocessor can not perform the evaluation properly. I'd suggest you stick to just checking definitions e.g. just use
#ifdef XXX
and when you need to use
#if
only use numerical constants, not any expressions.
FWIW as mentioned here https://en.wikipedia.org/wiki/C_preprocessor the preprocessor is quite limited - the reference discuss some of the limitations.
来源:https://stackoverflow.com/questions/65517700/why-is-this-program-produces-different-result-with-yes-and-true