Здесь вам задают два вопроса: один о константах и один о экстерне.Эти два понятия не обязательно связаны между собой.
Во-первых, const : константы не намного больше, чем, как вы сказали, они не могут быть изменены программно.Однако разные вещи могут быть постоянными, в зависимости от того, как вы их объявляете.Например, в вашем примере:
NSString * const MyConstant = @"foo";
вы объявили постоянный указатель на непостоянный объект NSString;ключевое слово const
находится справа от звезды, поэтому оно относится к указателю.Таким образом, это:
MyConstant = @"bar";
приведет к ошибке компиляции, поскольку он пытается переназначить MyConstant
, чтобы указать на другую строку NSString.
Если ключевое слово const
относится кслева от звезды он будет ссылаться на объект, на который ссылается указатель (в данном случае это базовая структура NSString).Это, вероятно, не то, что вам нужно в большинстве случаев в Задаче C. Обратите внимание, что позиция ключевого слова const
относительно идентификатора типа не имеет значения, поэтому это:
const NSString *MyConstant = @"foo";
, и это:
NSString const *MyConstant = @"foo";
означают одно и то же.Вы также можете юридически объявить как указатель, так и указанное значение const для максимальной константности:
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";
Это может быть полезно для констант, которые вы хотите использовать в одном файле реализации, но в других местах это не понадобится.