Objective-C中的保留关键字是什么?

16
昨天在CocoaHeads Öresund会议上,peylow建立了一个很棒的ObjC测验。竞争非常激烈,当最后一个问题需要评估时,有三个人得分相同:Objective-C添加了多少个保留关键字到C语言中?
随后进行了一些激烈的辩论。所有人都认为@interface@implementation等都是预处理器指令而不是关键字,但像in这样的东西呢?它可能是一个关键字,但它不是一个保留的关键字。例如,以下代码将可以编译通过,没有错误或警告:
NSArray* in;
for (in in in)
   NSLog(@"bwahahaa");

我们得出结论,ObjC没有为C添加任何保留关键字,并且有人赢得了一本看似实至名归的书。
但是今天我尝试通过这样的方式对编译器进行更系统化的滥用:
int self = 45;
self++;
int y = self;

这段代码可以顺利编译,如果将self替换为BOOL, bycopy, inout, oneway, byref, SEL,IMP,同样能够正常工作。

使用id作为变量名,第一行和最后一行可以编译通过,但是第二行不能。Protocol和Class也是一样的。

使用super,第一行可以编译通过,但是第二行和第三行不行。

对于YES、NO和NULL,这三行都无法编译通过,可能是因为它们只被定义为truefalsenil

在我看来,很多问题都是因为gcc混淆了判断,我不确定这是否反映了Objective-C中哪些是保留关键字。例如,为什么可以将self用作int类型的名称,但不能用super?

第一次赋值总是有效的(除了YES、NO和NULL),这似乎支持没有候选项是技术上未被保留的C关键字的想法。或者呢?

请有权威背景的人士给出关于这个棘手问题的明确解释。

有几个人的荣誉受到了挑战。

编辑:正如Nikolai Ruhe指出的那样,我们需要一个清晰的“关键字”定义才能继续。Niko引用了维基百科上的一篇文章,其中说关键字是“具有特定含义的单词或标识符”。

我认为可以使用同一篇文章中的这个定义:

在许多语言中,例如C和类似的环境(如C ++),关键字是标识语法形式的保留字。用于控制流结构的单词,例如if、then和else是关键字。在这些语言中,关键字不能用作变量或函数的名称。
此外,正如文章所述:
通常,当程序员尝试将关键字用作变量或函数名称时,会触发编译错误。
因此,是否有在语言的正式规范中预定义的保留关键字,不能用作用户定义的名称

这里有一些相关材料:https://dev59.com/OXVD5IYBdhLWcg3wTJvF - Felixyz
6个回答

10
所有人都认为@interface、@implementation等都是预处理器指令而不是关键字。
然而,他们都错了。#import和#pragma是预处理器指令。@interface、@implementation、@protocol等是Objective-C的关键字,它们是编译器指令。自从NeXT扩展GCC以在没有Stepstone原始Objective-C预处理器实现的情况下编译Objective-C以来,它们就不再是预处理器指令了。

那就意味着@interface是一个关键字(在上面的编辑中所述的意义上),但id不是,因为编译器拒绝编译例如“int @interface = 1;”但愉快地使用id作为int的名称。但是,编译器也不允许“int @icecream = 1;”。那么我们现在该怎么办呢? #import - 预处理指令 @interface - 编译器指令 @ - 保留字符 id/self/in - 在某些情况下具有特殊含义,但不是保留字 - Felixyz
id是一个typedef。你可以在objc.h中找到它。 - NSResponder

4

关于 Nikolai Ruhe 提出的 self 是一个关键字的建议

self 是 Objective-C 方法的一个类型为 id 的参数(类似于 _cmd 也是一个类型为 SEL 的参数),而不是关键字。 nil 是一个宏,可以扩展为 NULL。我有点失望的是,super 没有扩展为宏,也不是一个参数。

来自维基百科的条目:

Objective-C 是 C 语言的一层薄膜,而且更是 C 语言的一个严格超集。任何 C 语言程序都可以使用 Objective-C 编译器编译,并在 Objective-C 类中自由地包含 C 代码。

这将排除 Objective-C 向语言中添加任何受限制的关键字。


1
结论并不正确。一种语言的超集可以通过使用原始语言中非法的术语来添加关键字。这正是Objective-C所做的。 - Nikolai Ruhe
关于 super 不是宏的问题:编译器必须能够识别 super,因为它必须使用正确的消息类型(调用 objc_msgSendSuper 而不是 objc_msgSend)。super 指向与 self 相同的对象,因此没有必要将其作为另一个参数。 - Nikolai Ruhe
Objective-C作为超集并不排除它添加额外受限关键字,但允许所有C程序使用Objective-C编译器编译却不行。 - jon hohle
1
@Felixyz:在C函数中使用super作为变量名可以在gcc4.0、gcc4.2和clang中编译通过。当然,在方法中使用它是错误的。没有违反任何要求。我的意思是,Jon的推理是错误的:一个严格的超集可以添加关键字到语言中而不会破坏任何东西。 - Nikolai Ruhe
2
@Nikolai Ruhe:我承认你的观点:无论在方法内部 super 是否可以用作变量名都不重要,只要它在 C 函数中编译即可。而且 @ 不是 C 标识符中的有效字符,因此不允许将 @interface 等作为变量名也不会违反严格的子集要求。 - Felixyz
显示剩余4条评论

2
“Wikipedia”定义关键字为:
在计算机编程中,关键字是具有特定含义的单词或标识符。
我会将其翻译为:语言中的关键字是语法中的非终结符。(顺便说一下,语法本身并不包含“关键字”这个词,所以不会产生混淆)。
语法中的终结符是:(参见grammar
  • void:空的
  • char:字符
  • short:短整数
  • int:整数
  • long:长整数
  • float:单精度浮点数
  • double:双精度浮点数
  • signed:有符号的
  • unsigned:无符号的
  • id:标识符
  • const:常量
  • volatile:易变的
  • in:输入
  • out:输出
  • inout:输入输出
  • bycopy:按值传递
  • byref:按引用传递
  • oneway:单向的
  • self:自身
  • super:父类的
  • @interface:接口定义
  • @end:接口定义结束
  • @implementation:实现定义
  • @end:实现定义结束
  • @protocol:协议定义
  • @end:协议定义结束
  • @class:类声明

问题是ObjC可能会向C语言中添加哪些保留关键字。正如您在示例中所看到的,您可以自由地使用"in"作为变量名,因此它显然不算作保留关键字。 - Felixyz
1
我的意思是,"int float = 45;" 无法编译,而 "int id = 45;" 可以编译通过,这告诉我们一些信息。 - Felixyz
它们不是“示例”。据我所见,这是完整的列表。好吧,这取决于你认为什么是关键字。我已经给出了我的答案。 - nes1983
我指的是问题中的示例代码。“语言中的关键字是非终端符号”。你是指“终端符号”吗?我不认为任何人会称#define为关键字,那么为什么我们要将@interface视为关键字呢?感谢您的提供,但我并不信服。对我来说,任何可以用作变量名称的内容都不能成为(保留的)关键字。 - Felixyz
1
@Felixyz:回答你的问题需要先(通常)定义关键字这个术语。只有这样才能回答在Objective-C中什么是关键字。显然,对此存在不同的观点。 - Nikolai Ruhe

2
原书1995年版附录B中的语法将super定义为“文字符号”终端,并且它是消息接收器语法中的特例。 in 文字符号是ObjC 1.0中协议限定符的一部分,并在ObjC 2.0中被重用于快速枚举语法中(我认为它没有正式的语法定义)。 idvoidcharunsigned、typedefed类型等一起被定义为类型说明符。如果你把void称为关键字,那么id也是。

1
看一下Objective-C编程语言,你就会对可能或不可能实现的情况有一些线索。由于一些“关键词”在头文件中被定义,它们的替换可能会导致观察到的(和意外的)行为。

好的。所以问题是:Objective-C中是否有任何真正保留的关键字(除了已经在C中保留的关键字)? - Felixyz
1
没有像其他语言那样的保留关键词。它更像是可以与您的代码产生交互作用的定义。这完全取决于预处理器的工作。 - Laurent Etiemble

1
你可以查看Objective-C编程语言
据我所知,该文档没有将任何内容归类为“保留字”。@implementation@interface等被称为“编译器指令”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接