2015-03-28 2 views
0

Являются ли эти два кодовых блока эквивалентными? Что я в основном спрашиваю, так это, если я оставлю ключевое слово extern с globalVariable в случае 1, у него все еще есть внешний доступ? Единственное различие заключается в том, что когда вы оставляете ключевое слово 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 
+0

См http://stackoverflow.com/questions/496448/how-to-correctly-use-the-extern-keyword-in-c/499330#499330 – Rob

+0

BTW - это на самом деле вопрос C, а не вопрос Objective-C, поскольку Objective-C наследует эту функциональность от C. – rmaddy

ответ

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; 
+0

Я не получаю эту ошибку, когда оставляю extern out. Только когда я пытаюсь назначить globalVariable из 2-х мест. Если я оставлю все неназначенным, ошибка не возникает. – adrian

+1

Вы увидите это только в том случае, если вы поместите 'int globalVariable = 1' в' .h' файл _and include/import, который '.h' из двух разных файлов' .m'. – Rob

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;
Общий символ. Если для переменной есть только (один или несколько) общих символов, то она идет в неинициализированной области данных выходного файла . Компилятор объединяет несколько общих символов для одной и той же переменной в один символ. Если они имеют разные размеры, то выбирает самый большой размер. Компилятор превращает общий символ в объявление , если есть определение той же переменной.

Опция --warn-common может производить пять видов предупреждений. Каждое предупреждение состоит из пары строк: первый описывает только что встреченный символ , а второй описывает предыдущий символ , встречающийся с тем же именем. Один или оба из двух символов будут общим символом.

  1. Включение общего символа в ссылку, поскольку для символа уже существует определение.

       file(section): warning: common of `symbol' 
            overridden by definition 
           file(section): warning: defined here 
    
  2. Превращение общего символа в качестве ссылки, так как последующее определение для символа встречается. Это то же самое, что и предыдущий случай , за исключением того, что символы встречаются в другом порядке .

       file(section): warning: definition of `symbol' 
            overriding common 
           file(section): warning: common is here 
    
  3. Объединение общего символа с общим общим символом прежнего размера.

       file(section): warning: multiple common 
            of `symbol' 
           file(section): warning: previous common is here 
    
  4. Объединение общего символа с предыдущим более общим общим символом.

       file(section): warning: common of `symbol' 
            overridden by larger common 
           file(section): warning: larger common is here 
    
  5. Объединение общего символа с предыдущим меньшим общим символом. Это то же, что и в предыдущем случае, за исключением того, что символы встречаются в другом порядке.

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

Эй, спасибо за ответ. Умеет тонкость различий в размере данных, но не означает ли это, что int i = 1 в файле заголовка эквивалентен int i = 1 в файле реализации и extern int i в заголовке? – adrian

+0

Компилятор не знает о заголовках. Препроцессор просто передает его всей единицей перевода. Таким образом, все в заголовке такое же, как если бы оно было непосредственно в каждом исходном файле, который включает заголовок. На практике, конечно, заголовки включены в несколько исходных файлов. Таким образом, вам не нужны определения в файле заголовка, просто объявления. Другими словами, всегда используйте 'extern' и никакой инициализатор (например,' = 1') в заголовках. –

Смежные вопросы