Безобиден ли этот внешний вид?

main.h

extern int array[100];

main.c

#include "main.h"

int array[100] = {0};

int main(void)
{
    /* do_stuff_with_array */ 
}

В модуле main.c массив определяется и объявляется. Вызывает ли действие включение в модуль оператора extern каких-либо проблем?

Я всегда визуализировал оператор extern как команду компоновщику «искать в другом месте фактический именованный объект. Его здесь нет.

Что мне не хватает?

Спасибо.

Зло.


person EvilTeach    schedule 25.03.2009    source источник


Ответы (6)


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

Чтобы избежать раскрытия имен (переменных, функций, ..) вне определенного объекта (файла), вам придется использовать static.

person ypnos    schedule 25.03.2009
comment
Переменные, объявленные вне функции, ЯВЛЯЮТСЯ глобальными. - person alex; 25.03.2009
comment
Только если они являются внешними, в противном случае они являются локальными для единицы компиляции, в которой они находятся. - person BigSandwich; 26.03.2009
comment
да, но все же они глобальны в C. независимо от того, статичны они или нет. однако я не понимаю, какое отношение это имеет к этому ответу. также в C ++ переменные являются глобальными только тогда, когда они появляются в ::, а не в каком-то определенном пользователем пространстве имен. - person Johannes Schaub - litb; 26.03.2009
comment
Эти комментарии почти бесполезны просто потому, что global здесь не имеет значения. Имена имеют связь: нет, внутренняя, внешняя. - person Richard Corden; 26.03.2009
comment
+1, если вы не хотите показывать что-то в общедоступном заголовке, но нуждаетесь в этом в других модулях, поможет extern. Фактически, все в общедоступном заголовке (при связывании с его объектом) в любом случае технически является внешним. Ключевое слово дает больше гибкости. - person Tim Post♦; 28.03.2009
comment
Например: extern sig_atomic_t sig_caught .. зачем раскрывать это, когда все, что вы хотите сделать, это поместить обработчики сигналов в другой модуль? - person Tim Post♦; 28.03.2009
comment
Это отличное объяснение. Я никогда полностью не понимал, как extern работает, и теперь понимаю! - person ; 07.12.2009
comment
Единственное, чего не хватает в этом ответе, - это ответа на вопрос, который был задан на самом деле: вызывает ли действие включение в модуль оператора extern каких-либо проблем? Ответ: Нет. - person Adrian McCarthy; 08.12.2009

да, это безвредно. На самом деле, я бы сказал, что это довольно стандартный способ делать то, что вы хотите.

Как вы знаете, это просто означает, что любой файл .c, включающий main.h, также сможет увидеть array и получить к нему доступ.

person Evan Teran    schedule 25.03.2009

Изменить

И в C, и в C ++ наличие extern указывает, что первое объявление не является определением. Следовательно, он просто делает имя доступным в текущей единице перевода (любому, кто включает заголовок) и указывает, что упомянутый объект имеет внешнюю связь, то есть доступен во всех единицах перевода, составляющих программу. Это не говорит о том, что объект обязательно находится в другой единице перевода - просто «эта строка не является определением».

Завершить редактирование

В C extern не является обязательным. Без него первое объявление является «предварительным определением». Если бы не более позднее определение (которое однозначно является определением, потому что у него есть инициализатор), это рассматривалось бы как определение (C99 6.9.2). Как бы то ни было, это просто декларация и не противоречит.

В C ++ extern не является необязательным - без него первое объявление является определением (C ++ 03 3.1), которое конфликтует со вторым.

Это различие явно указано в Приложении C к C ++:

"Изменение: C ++ не имеет" предварительных определений ", как в C

Например, в области файла

int i;
int i;

допустимо в C, недопустимо в C ++. "

person fizzer    schedule 25.03.2009

Внешний вид безобидный и правильный. Вы не можете объявить это в заголовке без extern.

В качестве дополнения обычно рекомендуется создать макрос или константу для хранения размера массива; в вашем коде фактический размер (100) появляется дважды в исходной базе. Было бы чище сделать так:

#define ARRAY_SIZE 100

extern int array[ARRAY_SIZE];

...

int array[ARRAY_SIZE] = { 0 };

Но, возможно, вы не хотели включать это в фрагмент кода просто для краткости, поэтому не обижайтесь :)

person Antti Huima    schedule 25.03.2009


С точки зрения компиляции или исполнения это не имеет значения.

Однако это потенциально опасно, поскольку делает array [] доступным для любого другого файла, который #includes main.h, что может привести к изменению содержимого array [] в другом файле.

Итак, если array [] будет когда-либо использоваться только в main.c, удалите строку из main.h и объявите array [] как static в main.c.

Если array [] будет использоваться только в функции main (), объявите его там.

Другими словами, array [] должен иметь минимально возможную область видимости.

person Steve Melnikoff    schedule 28.03.2009
comment
+1 за предупреждение, когда его не использовать. Раньше я часто использовал его во встроенном коде, но это доставляло мне головную боль, беспокоясь о том, правильно ли я обращаюсь к нему. - person spade78; 22.02.2011