Разница между некоторой внешней переменной и статической переменной - PullRequest
2 голосов
/ 12 января 2012

Какая разница между внешней переменной некоторого вида и статической переменной?

//ClassA.m
NSString *var1;
static NSString *var2;

@implementation ClassA

...

Ответы [ 3 ]

3 голосов
/ 12 января 2012

extern

Константа / переменная extern - это та, к которой одно определение может быть обращено (или может быть использовано) в нескольких объектных файлах.Это глобальный экспортируемый символ C.Используйте это, если вы хотите получить доступ к постоянной / глобальной переменной из нескольких единиц перевода (или скомпилированных файлов) или если вы хотите использовать ее в нескольких двоичных файлах (например, вы хотите использовать ее из своего приложения, а определение находится в динамической библиотеке).Обычно вы объявляете это в заголовке, чтобы другие могли его использовать.

static

static создает копию для каждого перевода.Каждый скомпилированный файл, который также видит (например, #include d) статический объект, испускает копию этого статического элемента.Вам следует избегать этого.Это приведет к раздутому двоичному файлу с очень запутанным исполнением.Вы должны отдавать предпочтение статическому, если значение является локальным для файла и должно быть приватным для этого файла.

По этим причинам вы должны отдавать предпочтение static в своих .c, .m, .cpp и.mm файлы и extern в ваших заголовках.

Наконец, указатель NSString по умолчанию должен быть const:

// declaration - file.h
extern NSString * const var1;

// definition - file.m
NSString * const var1 = @"var1";

или

static NSString * const var2 = @"var2";

Если вам все еще нужно больше, вот соответствующий ответ, который я написал , а вот еще .

2 голосов
/ 12 января 2012

Глобальные переменные и static

Объявление переменной вне какого-либо метода (и в Objective-C внутри или снаружи @implementation / @end делает время жизни переменной глобальным, то есть переменная будет существовать во время весь период выполнения заявки.

Глобальная переменная без квалификации или только с квалификаторами const и / или volatile, видима из любого места. Так, например:

NSString *MyApplicationName;

объявляет глобальную переменную MyApplicationName, к которой можно получить доступ из любого места приложения.

Видимость глобальной переменной (но не ее времени жизни) может быть ограничена только файлом (точнее, «единицей компиляции», допускающим один файл, включая другие), содержащим объявление, квалифицируя его как static. Так, например:

static NSString *MyClassName;

объявляет глобальную переменную MyClassName, которая видна только из текущего модуля компиляции.

Использование static квалифицированных глобальных объявлений в @implementation / @end является наиболее близкой вещью, которую Objective-C предлагает к "переменным класса" других языков.

Вы не должны размещать объявления глобальных переменных, квалифицированных static или нет, в заголовочных файлах, так как это приведет к нескольким различным объявлениям - возникнет ошибка, если нет квалификатора static, и несколько различных переменных с разными областями видимости, если таковая имеется.

Классификатор extern

Спецификатор extern делает что-то совсем другое.

Первоначальный смысл (теперь допускается небольшое ослабление, см. Ниже) - просто определить тип и имя глобальной переменной, которая объявлена ​​в другом месте. То есть вы говорите компилятору «есть глобальная переменная некоторого типа и имени, которую я хотел бы использовать, которая будет предоставлена ​​другим модулем компиляции». Например:

extern NSString *MyApplicationName;

заявляет, что некоторая единица компиляции содержит объявление (которое не должно быть static квалифицированным):

NSString *MyApplicationName;

Квалифицированное объявление extern само по себе не вызывает выделение какого-либо хранилища для глобальной переменной.

Вы делаете размещаете extern квалифицированные объявления в заголовочных файлах, вот как модуль компиляции объявляет глобальные переменные, которые он хочет экспортировать. Вы также можете поместить их в файлы кода для ссылки на глобальные переменные, объявленные в другом месте. В файле кода вы можете поместить квалифицированное объявление extern вне любого метода / функции - в этом случае имя / тип доступно для всей единицы компиляции - или внутри метода / функции - в этом случае видимость имя / тип ограничено только этим методом / функцией.

Небольшое расслабление

Изначально вам нужно было одно не extern объявление квалификатора, чтобы удовлетворить любые extern квалифицированные. Однако это было позже изменено, если при связывании различных модулей компиляции ни один из них не объявляет глобальную переменную, на которую ссылается какое-то квалифицированное объявление extern, то компоновщик (обычно?) Просто генерирует саму переменную и добавляет ее в результирующий двоичный файл, а не выдает «отсутствующую глобальную» ошибку. Лучшая практика программирования - не полагаться на это ослабление - всегда иметь квалифицированное объявление, не являющееся extern для каждой глобальной переменной.

1 голос
/ 12 января 2012

Я мог бы дать объяснение, но оно было бы не так хорошо, как это:

http://blog.ablepear.com/2010/01/objective-c-tuesdays-static-variables.html

...