【发布时间】:2012-01-12 03:51:48
【问题描述】:
某种外部变量和静态变量有什么区别?
//ClassA.m
NSString *var1;
static NSString *var2;
@implementation ClassA
...
【问题讨论】:
标签: objective-c variables static constants extern
某种外部变量和静态变量有什么区别?
//ClassA.m
NSString *var1;
static NSString *var2;
@implementation ClassA
...
【问题讨论】:
标签: objective-c variables static constants extern
extern 常量/变量是可以跨多个目标文件访问(或引用)的一个定义。它是一个全局的、导出的 C 符号。如果您想从多个翻译单元(或编译文件)访问常量/全局变量,或者如果您想在多个二进制文件中使用它(例如,您想从您的应用程序中使用它,并且定义在动态库中,请使用此选项) )。您通常会在标题中声明它以供其他人使用。
static 为每个翻译发出一个副本。每个编译的文件也看到(例如#included)静态将发出该静态的副本。你应该避免这种情况。这将导致执行非常混乱的臃肿二进制文件。如果值是文件的本地值,您应该支持静态值,并且应该是该文件的私有值。
出于这些原因,您应该在 .c、.m、.cpp 和 .mm 文件中使用 static,在标题中使用 extern。
最后,NSString 指针默认应该是const:
// declaration - file.h
extern NSString * const var1;
// definition - file.m
NSString * const var1 = @"var1";
或
static NSString * const var2 = @"var2";
如果您还想要更多,here's a related answer I wrote 和 here's another。
【讨论】:
extern 限定符本身并没有声明一个变量具有全局可见性(上面的“链接”)——没有extern 的全局变量具有全局可见性。但是,如果您选择像对待它一样对待它,您可能不会出错。我的回答中有更多详细信息。
extern 限定定义,以及一个或多个引用该全局变量的extern 限定声明。 IE。与方法/函数等效的模式 - 一处定义主体,一处或多处使用原型引用方法/函数。在这两种情况下,“一个或多个”通常意味着仅在定义全局/方法/函数的代码文件的标头中。现在放松允许你将extern添加到def中,但这并没有什么意义。
全局变量和static
在任何方法之外声明一个变量(在 Objective-C 内部或外部,@implementation/@end 使变量的生命周期成为全局变量,即该变量将存在在应用程序执行的整个时间段内。
一个没有限定的全局变量,或者只有const 和/或volatile 限定符,在任何地方都是可见的。比如:
NSString *MyApplicationName;
声明一个全局变量MyApplicationName,可以从应用程序的任何地方访问。
通过使用static 限定一个全局变量(而不是它的生命周期)的可见性,可以将其限制为仅包含包含声明的文件(更准确地说是“编译单元”,允许一个文件包括其他文件)。比如:
static NSString *MyClassName;
声明一个全局变量MyClassName,它只在当前编译单元中可见。
在@implementation/@end 中使用static 限定的全局声明是Objective-C 提供的最接近其他语言的“类变量”的东西。
您不应将全局变量声明(static 限定与否)放在头文件中,因为这会导致多个不同的声明 - 如果没有 static 限定符,则会导致错误,以及具有不同可见性范围的多个不同变量(如果有的话)。
extern 限定符
extern 限定符做了一些完全不同的事情。
原来的意思(现在允许稍微放宽,见下文)只是定义一个在别处声明的全局变量的type和name。那就是你告诉编译器“有一个我想使用的某种类型和名称的全局变量将由另一个编译单元提供”。例如:
extern NSString *MyApplicationName;
声明某些编译单元包含声明(不得为static 限定):
NSString *MyApplicationName;
extern 限定声明本身不会导致为全局变量分配任何存储空间。
您做在头文件中放置extern 限定声明,这是编译单元如何通告它希望导出的全局变量。您还可以将它们放在代码文件中以引用在其他地方声明的全局变量。在代码文件中,您可以在任何方法/函数之外放置extern 限定声明 - 在这种情况下,名称/类型可用于整个编译单元 - 或在方法/函数中 - 在这种情况下,名称/类型仅限于该方法/功能。
小放松
最初您必须有一个非extern 限定符声明才能满足任何extern 限定符声明。然而,这后来被改变了,如果在将各种编译单元链接在一起时,它们都没有声明由某些 extern 限定声明引用的全局变量,那么链接器(通常?)只是生成变量本身并将其添加到生成的二进制文件中,而不是产生“缺少全局”错误。最佳编程实践是不要依赖这种放松 - 始终对每个全局变量都有一个 none-extern 限定声明。
【讨论】:
【讨论】: