让extern脱离全局变量

时间:2015-03-28 02:13:49

标签: objective-c

这两个代码块是否相同?我基本上要问的是,如果我在案例1中将extern关键字从globalVariable中删除,它是否仍然具有外部访问权限?唯一的区别是当你离开extern关键字时,你可以初始化变量吗?

int globalVariable = 1;

@interface Square : Rectangle
-(instancetype) initWithSide: (int) s;
-(void) setSide: (int) s;
-(int) side;
@end



extern int globalVariable;
@interface Square : Rectangle
-(instancetype) initWithSide: (int) s;
-(void) setSide: (int) s;
-(int) side;
@end

2 个答案:

答案 0 :(得分:2)

不,这些不一样。

如果这是一个全局版,您将在.h中引用,则可以使用extern引用。如果您在没有.h关键字的extern中声明此全局,但是从多个.h文件中包含此.m,那么您最终会发出有关重复的警告符号,如:

duplicate symbol _globalVariable in:
    /Users/.../Library/Developer/Xcode/DerivedData/...-eplmsbsfhnuvekewnlgooclttbpr/Build/Intermediates/....build/Debug-iphonesimulator/....build/Objects-normal/x86_64/ViewController.o
    /Users/.../Library/Developer/Xcode/DerivedData/...-eplmsbsfhnuvekewnlgooclttbpr/Build/Intermediates/....build/Debug-iphonesimulator/....build/Objects-normal/x86_64/AppDelegate.o
duplicate symbol _globalVariable in:
    /Users/.../Library/Developer/Xcode/DerivedData/...-eplmsbsfhnuvekewnlgooclttbpr/Build/Intermediates/....build/Debug-iphonesimulator/....build/Objects-normal/x86_64/ViewController.o
    /Users/.../Library/Developer/Xcode/DerivedData/...-eplmsbsfhnuvekewnlgooclttbpr/Build/Intermediates/....build/Debug-iphonesimulator/....build/Objects-normal/x86_64/main.o
ld: 2 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

因此,正确的方法是将extern放在.h文件中(因此包含此标头的任何.m文件都可以看到全局):

extern int globalVariable; 

然后只初始化一次,在.m文件中执行此操作,该文件对应于您声明它的.h文件:

int globalVariable = 1;

显然,如果您打算仅使用一个.m文件中的全局,那么您可以在一个.m文件中定义它(但通常使用static来确保它范围有限):

static int globalVariable = 1;

答案 1 :(得分:0)

文件范围内的

int foo;是“常用”符号的声明

文件范围内的

int foo = 1;是符号的定义(带有外部链接)。

文件范围内的

extern int foo;是外部符号的声明

通常,应避免使用常用符号。

据我所知,如果链接器找到了常见的符号引用但没有定义它,那么它将使一个没有警告。

相比之下,必须有一个定义才能满足对外部符号的引用。


为了更加清晰,我将引用the GNU ld manual's explanation of its --warn-common option

  

--warn-common
      当公共符号与另一个公共符号或符号定义组合时发出警告。 Unix连接器允许这有点草率   实践,但其他一些操作系统上的链接器没有。这个   选项允许您通过组合全局来发现潜在的问题   符号。不幸的是,一些C库使用这种做法,所以你可以   得到一些关于图书馆和你的符号的警告   程序

     

有三种全局符号,这里用C示例说明:

     

int i = 1;
          定义,位于输出文件的初始化数据部分。

     

extern int i;
          未定义的引用,不分配空间。变量必须有定义或公共符号   某处。

     

int i;
          一个共同的象征。如果变量只有(一个或多个)公共符号,则它会进入未初始化的数据区域   输出文件。链接器合并多个公共符号   变量为单个符号。如果它们的大小不同,那就是它   选择最大的尺寸。链接器将公共符号转换为a   声明,如果有相同变量的定义。

     

--warn-common选项可以产生五种警告。每个警告由一对线组成:第一个描述了   刚刚遇到的符号,第二个描述了前一个符号   遇到同名的。两个符号中的一个或两个将是   一个共同的符号。

     
      
  1. 将公共符号转换为引用,因为已经有符号的定义。

                   file(section): warning: common of `symbol'
                      overridden by definition
                   file(section): warning: defined here
    
  2.   
  3. 将公共符号转换为引用,因为会遇到符号的后续定义。这和   之前的情况,除了符号遇到不同的情况   顺序。

                   file(section): warning: definition of `symbol'
                      overriding common
                   file(section): warning: common is here
    
  4.   
  5. 将公共符号与之前相同大小的公共符号合并。

                   file(section): warning: multiple common
                      of `symbol'
                   file(section): warning: previous common is here
    
  6.   
  7. 将公共符号与之前较大的公共符号合并。

                   file(section): warning: common of `symbol'
                      overridden by larger common
                   file(section): warning: larger common is here
    
  8.   
  9. 将公共符号与先前较小的公共符号合并。除了符号之外,这与前一种情况相同   以不同的顺序遇到。

                   file(section): warning: common of `symbol'
                      overriding smaller common
                   file(section): warning: smaller common is here
    
  10.