为什么这个程序用 `YES` 和 `true` 产生不同的结果?
Why is this program produces different result with `YES` and `true`?
这是完整的程序。你能算出它的控制台输出吗?
#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;
}
在继续之前,您可以复制粘贴,运行,然后自己检查结果。
输出为:
x: xyz; y: abc
abc
abc
谁能解释一下原因?
如果你添加
#define YES 1
一开始你会得到你期望的输出。原因是 YES
定义可能比这里给出的方式更复杂,这会扰乱预处理器。您可以通过例如将您的测试更改为
#if YES
(并删除我对 YES 的定义),您会得到与之前相同的结果。这只是表明,无论如何定义 YES
,它都不会触发
#if YES
测试。
PS
我想如果你想使用常量,例如
#if XXX
或
#if XXX > 5
您需要将 XXX
定义为数值,否则预处理器无法正确执行计算。我建议你坚持只检查定义,例如只需使用
#ifdef XXX
以及何时需要使用
#if
只使用数值常量,不使用任何表达式。
此处提到的 FWIW https://en.wikipedia.org/wiki/C_preprocessor 预处理器非常有限 - 参考讨论了一些限制。
YES
在 中被定义为 __objc_yes
,这是编译器级别的符号,预处理器不知道。
(/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/objc/objc.h 在我的机器上。)
你可以通过
看到定义
#define T(X) #X
#define S(X) T(X)
printf("YES is: \"%s\"\n", S(YES));
C 预处理器是一个有趣的野兽。 :)
编辑:为什么
#if __objc_yes
表现得好像 __objc_yes
是假的?因为 __objc_yes
对预处理器来说是完全未知的;只有编译器知道。这是从 manual 到 GNU 预处理器,但我相信它反映了标准,关于 #if
之后的表达式可以包含什么:
[...] Identifiers that are not macros, which are all considered to be the number zero. [...]
这是完整的程序。你能算出它的控制台输出吗?
#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;
}
在继续之前,您可以复制粘贴,运行,然后自己检查结果。
输出为:
x: xyz; y: abc
abc
abc
谁能解释一下原因?
如果你添加
#define YES 1
一开始你会得到你期望的输出。原因是 YES
定义可能比这里给出的方式更复杂,这会扰乱预处理器。您可以通过例如将您的测试更改为
#if YES
(并删除我对 YES 的定义),您会得到与之前相同的结果。这只是表明,无论如何定义 YES
,它都不会触发
#if YES
测试。
PS
我想如果你想使用常量,例如
#if XXX
或
#if XXX > 5
您需要将 XXX
定义为数值,否则预处理器无法正确执行计算。我建议你坚持只检查定义,例如只需使用
#ifdef XXX
以及何时需要使用
#if
只使用数值常量,不使用任何表达式。
此处提到的 FWIW https://en.wikipedia.org/wiki/C_preprocessor 预处理器非常有限 - 参考讨论了一些限制。
YES
在 __objc_yes
,这是编译器级别的符号,预处理器不知道。
(/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/objc/objc.h 在我的机器上。)
你可以通过
看到定义#define T(X) #X
#define S(X) T(X)
printf("YES is: \"%s\"\n", S(YES));
C 预处理器是一个有趣的野兽。 :)
编辑:为什么
#if __objc_yes
表现得好像 __objc_yes
是假的?因为 __objc_yes
对预处理器来说是完全未知的;只有编译器知道。这是从 manual 到 GNU 预处理器,但我相信它反映了标准,关于 #if
之后的表达式可以包含什么:
[...] Identifiers that are not macros, which are all considered to be the number zero. [...]