Внешняя декларация на внешнем «C» глобальная переменная

В C и C ++, если я хочу использовать глобальную переменную в других модулях компиляции, я определю переменную следующим образом:

int g_myVal = 0;

Это выделяет память для int,

Затем в заголовочном файле я объявляю переменную:

extern int g_myVal;

Это сообщает компилятору, что указанный символ существует в каком-то другом модуле компиляции. Затем компоновщик должен разрешить символ.

Однако, если я хочу, чтобы переменная была доступна со связью «C», я должен определить переменную (выделить хранилище), например:

extern "C" int g_myVal = 0;

Так как же тогда отличить выделение памяти от простого информирования компилятора о том, что указанный символ существует в другом модуле компиляции?

3

Решение

Ваша путаница проистекает из того факта, что extern а также extern "C" сделать две разные вещи.


Около extern

extern сам по себе является спецификатор класса хранения:

[C++11: 7.1.1/6]: extern Спецификатор может применяться только к именам переменных и функций. extern спецификатор нельзя использовать в объявлении членов класса или параметров функции. Для связи имени, объявленного с extern спецификатор, см. 3.5. [ Заметка: extern Ключевое слово также может быть использовано в Явная-конкретизация а также сцепления-спецификации, но это не хранения класса спецификатор в таких контекстах. —Конечная записка]


Около extern "C"

Как намекает на это заключительное примечание, существует другой контекст, в котором вы можете использовать extern Ключевое слово, и это как спецификатор связи:

[C++11: 7.5/2]: Связь (3.5) между фрагментами кода C ++ и не-C ++ может быть достигнута с помощью Связь-спецификация:

Связь-спецификации:
    extern Строка литерала { Заявление-слвыбирать }
    extern строково-буквенное объявление

C ++ любит повторно использовать ключевые слова.


Объявления против определений

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

[C++11: 7.5/7]: Декларация, непосредственно содержащаяся в Связь-спецификация рассматривается как если бы он содержал extern спецификатор (7.1.1) с целью определения связи объявленного имени и определения, является ли оно определением. Такое объявление не должно указывать класс хранения. [ Пример:

extern "C" double f();
static double f(); // error
extern "C" int i; // declaration
extern "C" {
int i; // definition
}
extern "C" static void g(); // error

— конец примера]

Как вы можете видеть в приведенном выше примере, все еще возможно или объявление или определение, когда вы используете спецификатор связи.

Вот еще один пример этого:

// Everything in this block has C linkage
extern "C" {

// Declaration of g_myVal
extern int g_myVal;

// Definition of g_myVal2
int g_myVal2;
}

int main()
{
g_myVal2 = 5;  // ok
g_myVal  = 6;  // not okay - linker error, symbol not found
}

Живая демо


Когда вы добавляете инициализатор …

Это все, как говорится, лечение g_myVal как декларация является отменено с помощью использования инициализатора, который заставляет заявление быть определением:

[C++11: 7/8]: Синтаксические компоненты помимо тех, которые находятся в общем виде объявления, добавляются к объявлению функции для определения функции. Объявление объекта, однако, также является определением, если оно не содержит extern спецификатор и не имеет инициализатора (3.1). Определение заставляет зарезервировать соответствующий объем памяти и выполнить любую соответствующую инициализацию (8.5).

Я надеюсь, что это проясняет, что происходит в вашем коде с этими различными значениями extern,

7

Другие решения

В этом случае ставим инициализатор = 0 изменил объявление на определение, поэтому здесь выделено хранилище. (То же самое случилось бы даже с просто extern.)

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector