为啥这个程序会产生与 `YES` 和 `true` 不同的结果?

Posted

技术标签:

【中文标题】为啥这个程序会产生与 `YES` 和 `true` 不同的结果?【英文标题】:Why is this program produces different result with `YES` and `true`?为什么这个程序会产生与 `YES` 和 `true` 不同的结果? 【发布时间】:2020-12-31 07:04:20 【问题描述】:

这是完整的程序。你能弄清楚它的控制台输出吗?

#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

谁能解释一下原因?

【问题讨论】:

看完这篇clang doc (clang.llvm.org/docs/ObjectiveCLiterals.html#discussion),我更加困惑了。也许这与预处理器指令#if 的工作方式有关。我不知道。 【参考方案1】:

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 之后的表达式可以包含什么:

[...] 不是宏的标识符,它们都被认为是数字零。 [...]

【讨论】:

等等,我可以用#define kEnv __objc_yes 替换#define kEnv YES。还有,为什么#if __objc_yes 被评估为负数?【参考方案2】:

如果你添加

#define YES 1

一开始你会得到你期望的输出。原因是YES 的定义可能比这里给出的方式更复杂,这会弄乱预处理器。您可以通过例如测试它将您的测试更改为

#if YES

(并删除我对“是”的定义),您将获得与之前相同的结果。这只是表明,尽管定义了YES,但它不会触发

#if YES

测试。

附言

我想如果你想使用常量,例如

#if XXX

#if XXX > 5

您需要将XXX 定义为数值,否则预处理器无法正确执行评估。我建议你坚持只检查定义,例如只需使用

#ifdef XXX

以及何时需要使用

#if

只使用数字常量,不使用任何表达式。

这里提到的 FWIW https://en.wikipedia.org/wiki/C_preprocessor 预处理器非常有限 - 参考讨论了一些限制。

【讨论】:

好的,我找不到YES 定义,但我知道你明白了。 我不是在寻找正确的方法。我想知道这是如何工作的。重新定义YES 并不能说明原因。 好的,看看我刚刚添加的PS

以上是关于为啥这个程序会产生与 `YES` 和 `true` 不同的结果?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个 Haskell 程序会产生反斜杠?

为啥“true && () => ”会产生“Uncaught SyntaxError: Malformed arrow function parameter list”? [复制

为啥这个事务会产生死锁?

为啥这个看似简单的 C++ 代码会产生分段错误?

你能解释一下为啥 DirectoryInfo.GetFiles 会产生这个 IOException 吗?

为啥 glutSolidTorus 会产生一些缺陷