Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explanation of constants

I have been looking about constants and I don't really understand whats different about them other than they cant be changed programmatically.

extern NSString * const MyConstant;

With this line what exactly does extern mean and what exactly does the const mean?

like image 866
Jonathan. Avatar asked Nov 30 '22 09:11

Jonathan.


1 Answers

You're asked two questions here: one about constants and one about extern. The two aren't necessarily related.

First, const: there isn't much more to constants than, as you said, they can't be changed programmatically. Different things can be constant though, depending on how you declare them. For instance, in your example:

NSString * const MyConstant = @"foo";

you have declared a constant pointer to a non-constant NSString object; the const keyword is to the right of the star, so it refers to the pointer. Thus, this:

MyConstant = @"bar";

would result in a compile error, since it's attempting to reassign MyConstant to point to a different NSString.

If the const keyword were to the left of the star it would refer to the object the pointer references (in this case, the underlying NSString struct). This probably isn't what you want most of the time in Objective C. Note that the position of the const keyword relative to the type identifier doesn't matter, so this:

const NSString *MyConstant = @"foo";

and this:

NSString const *MyConstant = @"foo";

mean the same thing. You can also legally declare both the pointer and the referenced value const, for maximum constness:

const NSString * const MyConstant = @"foo";

Second, extern: extern simply allows you to declare a variable in one compilation unit, and let the compiler know that you've defined that variable in a separate compilation unit. You would generally use this only for global values and constants.

You can think of a compilation unit as a single .m file, as well as all the .h files it includes. At build time the compiler compiles each .m file into a separate .o file, and then the linker hooks them all together into a single binary. Usually the way one compilation unit knows about identifiers (such as a class name) declared in another compilation unit is by importing a header file. But, in the case of globals, they are often not part of a class's public interface, so they're frequently declared and defined in a .m file.

If compilation unit A declares a global in a .m file:

#import "A.h"

NSString *someGlobalValue;

and compilation unit B wants to use that global:

#import "B.h"
extern NSString *someGlobalValue;

@implementation B

- (void)someFunc {
    NSString *localValue = [self getSomeValue];
    if (localValue isEqualToString:someGlobalValue]) {
        ...
    }
}

unit B has to somehow tell the compiler to use the variable declared by unit A. It can't import the .m file where the declaration occurs, so it uses extern to tell the compiler that the variable exists elsewhere.

Note that if unit A and unit B both have this line at the top level of the file:

NSString *someGlobalValue;

then you have two compilation units declaring the same global variable, and the linker will fail with a duplicate symbol error. If you want to have a variable like this that exists only inside a compilation unit, and is invisible to any other compilation units (even if they use extern), you can use the static keyword:

static NSString * const someFileLevelConstant = @"wibble";

This can be useful for constants that you want to use within a single implementation file, but won't need elsewhere.

like image 186
Adam Milligan Avatar answered Dec 05 '22 00:12

Adam Milligan