adrian
adrian

Reputation: 2376

Leaving the extern off of a global variable

Are these two code blocks equivalent? What I'm basically asking is since that if I leave the extern keyword off of globalVariable in case 1, does it still have extern access? The only difference being when you leave the extern keyword off you are allow to initialize the variable?

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

Upvotes: 0

Views: 212

Answers (2)

Ken Thomases
Ken Thomases

Reputation: 90531

int foo; at file scope is a declaration of a "common" symbol.

int foo = 1; at file scope is a definition of a symbol (with external linkage).

extern int foo; at file scope is a declaration of an external symbol.

In general, common symbols should be avoided.

As I understand it, if the linker finds common symbol references but no definition for it, it will make one with no warning.

By contrast, there must be exactly one definition to satisfy references to external symbols.


For greater clarity, I'll quote from the GNU ld manual's explanation of its --warn-common option:

--warn-common
Warn when a common symbol is combined with another common symbol or with a symbol definition. Unix linkers allow this somewhat sloppy practice, but linkers on some other operating systems do not. This option allows you to find potential problems from combining global symbols. Unfortunately, some C libraries use this practice, so you may get some warnings about symbols in the libraries as well as in your programs.

There are three kinds of global symbols, illustrated here by C examples:

int i = 1;
A definition, which goes in the initialized data section of the output file.

extern int i;
An undefined reference, which does not allocate space. There must be either a definition or a common symbol for the variable somewhere.

int i;
A common symbol. If there are only (one or more) common symbols for a variable, it goes in the uninitialized data area of the output file. The linker merges multiple common symbols for the same variable into a single symbol. If they are of different sizes, it picks the largest size. The linker turns a common symbol into a declaration, if there is a definition of the same variable.

The --warn-common option can produce five kinds of warnings. Each warning consists of a pair of lines: the first describes the symbol just encountered, and the second describes the previous symbol encountered with the same name. One or both of the two symbols will be a common symbol.

  1. Turning a common symbol into a reference, because there is already a definition for the symbol.

                   file(section): warning: common of `symbol'
                      overridden by definition
                   file(section): warning: defined here
    
  2. Turning a common symbol into a reference, because a later definition for the symbol is encountered. This is the same as the previous case, except that the symbols are encountered in a different order.

                   file(section): warning: definition of `symbol'
                      overriding common
                   file(section): warning: common is here
    
  3. Merging a common symbol with a previous same-sized common symbol.

                   file(section): warning: multiple common
                      of `symbol'
                   file(section): warning: previous common is here
    
  4. Merging a common symbol with a previous larger common symbol.

                   file(section): warning: common of `symbol'
                      overridden by larger common
                   file(section): warning: larger common is here
    
  5. Merging a common symbol with a previous smaller common symbol. This is the same as the previous case, except that the symbols are encountered in a different order.

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

Upvotes: 0

Rob
Rob

Reputation: 437482

No, these are not the same.

If this is a global you're going to reference in a .h, you would use an extern reference. If you declare this global in the .h without the extern keyword, but then include this .h from multiple .m files, then you're going to end up warnings about duplicate symbols, like so:

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)

So, the correct way to do this is to put the extern in the .h file (so any .m files that include this header get visibility to the global):

extern int globalVariable; 

But then initialize it only once, doing this in the .m file that corresponds to the .h file in which you declared it:

int globalVariable = 1;

Clearly, if you were going to use this global from only one .m file, then you'd define it within that one .m file (but usually with static to ensure its scope was limited):

static int globalVariable = 1;

Upvotes: 2

Related Questions