Это экстерьер безвреден? - PullRequest
5 голосов
/ 25 марта 2009

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 как команду компоновщику «искать в другом месте фактическую именованную сущность. Здесь ее нет.

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

Спасибо.

Evil.

Ответы [ 6 ]

26 голосов
/ 25 марта 2009

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

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

9 голосов
/ 25 марта 2009

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

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

6 голосов
/ 26 марта 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 ++. "

4 голосов
/ 25 марта 2009

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

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

#define ARRAY_SIZE 100

extern int array[ARRAY_SIZE];

...

int array[ARRAY_SIZE] = { 0 };

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

2 голосов
/ 26 марта 2009
1 голос
/ 28 марта 2009

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

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

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

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

Другими словами, область действия массива [] должна быть ограничена наименьшим возможным значением.

...