【发布时间】:2010-12-04 16:06:24
【问题描述】:
我一直在寻找常量,但我真的不明白它们有什么不同,除了它们不能以编程方式更改。
extern NSString * const MyConstant;
在这一行中,extern 到底是什么意思,const 到底是什么意思?
【问题讨论】:
标签: objective-c constants
我一直在寻找常量,但我真的不明白它们有什么不同,除了它们不能以编程方式更改。
extern NSString * const MyConstant;
在这一行中,extern 到底是什么意思,const 到底是什么意思?
【问题讨论】:
标签: objective-c constants
您在这里被问到两个问题:一个是关于常量的,一个是关于 extern 的。两者不一定相关。
首先,const:常量没有什么比你说的不能以编程方式更改的更多的了。但是,不同的事物可能是不变的,这取决于您如何声明它们。例如,在您的示例中:
NSString * const MyConstant = @"foo";
你已经声明了一个指向非常量 NSString 对象的常量指针; const 关键字在星号的右边,所以它指的是指针。因此,这是:
MyConstant = @"bar";
会导致编译错误,因为它试图重新分配 MyConstant 以指向不同的 NSString。
如果const 关键字位于星号的左侧,它将引用指针所引用的对象(在本例中为底层 NSString 结构)。这可能不是您在 Objective C 中大部分时间想要的。请注意,const 关键字相对于类型标识符的位置无关紧要,因此:
const NSString *MyConstant = @"foo";
还有这个:
NSString const *MyConstant = @"foo";
意思是一样的。您还可以合法地声明指针和引用的值 const,以获得最大的 constness:
const NSString * const MyConstant = @"foo";
其次,extern:extern 只允许您在一个编译单元中声明一个变量,并让编译器知道您已在一个单独的编译单元中定义了该变量。您通常只会将其用于全局值和常量。
您可以将编译单元视为单个.m 文件,以及它包含的所有.h 文件。在构建时,编译器将每个 .m 文件编译成一个单独的 .o 文件,然后链接器将它们全部挂钩到一个二进制文件中。通常一个编译单元知道在另一个编译单元中声明的标识符(例如类名)的方式是导入一个头文件。但是,对于全局变量,它们通常不是类的公共接口的一部分,因此它们经常在.m 文件中声明和定义。
如果编译单元 A 在 .m 文件中声明一个全局变量:
#import "A.h"
NSString *someGlobalValue;
并且编译单元 B 想要使用该全局:
#import "B.h"
extern NSString *someGlobalValue;
@implementation B
- (void)someFunc {
NSString *localValue = [self getSomeValue];
if (localValue isEqualToString:someGlobalValue]) {
...
}
}
单元 B 必须以某种方式告诉编译器使用单元 A 声明的变量。它无法导入声明所在的 .m 文件,因此它使用 extern 告诉编译器该变量存在于别处.
请注意,如果单元 A 和单元 B 都在文件的顶层有这一行:
NSString *someGlobalValue;
那么您有两个编译单元声明了相同的全局变量,链接器将因重复符号错误而失败。如果你想有一个像这样的变量只存在于一个编译单元中,并且对任何其他编译单元不可见(即使它们使用extern),你可以使用static关键字:
static NSString * const someFileLevelConstant = @"wibble";
这对于您想在单个实现文件中使用但在其他地方不需要的常量很有用。
【讨论】:
extern NSString * const MyConstant;
您会在头文件中看到这一点。它告诉编译器变量MyConstant 存在并且可以在你的实现文件中使用。
变量的设置很可能是这样的:
NSString * const MyConstant = @"foo";
该值无法更改。如果您想要一个可以更改的全局变量,请从声明中删除 const。
【讨论】:
extern。 extern 关键字的存在是为了允许链接器解析跨翻译单元使用的符号。如果符号在头文件中声明,则无需使用extern;只需导入头文件。而且,不需要使用extern 将符号导入头文件,因为全局变量不是类接口的一部分。
extern 表示变量设置在声明它的源文件之外。建议使用 OBJC_EXPORT 标志而不是 extern。
Const 表示变量设置后不能更改。但是,您可以使用一些指针误导,如下所示:
NSString **var = (NSString **)&MyConstant;
*var = @"I changed it!";
如果您需要,这实际上允许您更改它(例如,在您的类中 +initialize 方法)。
【讨论】: