Определение переменной в заголовочных файлах - PullRequest
24 голосов
/ 07 февраля 2010

Мои самые базовые знания C и процесса компиляции за последнее время стали ржавыми. Я пытался найти ответ на следующий вопрос, но не смог соединить основы компиляции, связывания и предварительной обработки. Быстрый поиск в Google тоже не сильно помог. Итак, я решил прийти к первоисточнику знаний :)

Я знаю: Переменные не должны быть определены в файлах .h. Можно объявить их там.

Почему: Поскольку заголовочный файл может быть включен из нескольких мест, переопределение переменной происходит более одного раза (компоновщик выдает ошибку).

Возможный обходной путь: Используйте защиту заголовков в файлах заголовков и определите переменную в них.

Действительно ли это решение: Нет. Потому что защита заголовков предназначена для фазы предварительной обработки. То есть сообщить компилятору, что эта часть уже включена, и не включать его еще раз. Но наша ошибка в множественном определении возникает в части компоновщика - много после компиляции.

Все это запутало меня из-за того, как работает предварительная обработка и компоновка. Я думал, что предварительная обработка просто не будет включать код, если символ защиты заголовка был определен. В таком случае, не должно ли быть решено многократное определение переменной?

Что происходит, когда эти директивы предварительной обработки спасают процесс компиляции от переопределения символов под защитой заголовка, но компоновщик все же получает несколько определений символа?

Ответы [ 4 ]

26 голосов
/ 07 февраля 2010

Одна вещь, которую я использовал в прошлом (когда глобальные переменные были в моде):

файл var.h:

...
#ifdef DEFINE_GLOBALS
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int global1;
EXTERN int global2;
...

Затем в один .c файл (обычно тот, который содержит main ()):

#define DEFINE_GLOBALS
#include "var.h"

Остальные исходные файлы обычно включают «var.h».

Обратите внимание, что DEFINE_GLOBALS не является защитой заголовка, а скорее позволяет объявлять / определять переменные в зависимости от того, определена ли она. Этот метод позволяет одну копию объявлений / определений.

24 голосов
/ 07 февраля 2010

Защита заголовка защищает вас от нескольких включений в одном исходном файле, а не от нескольких исходных файлов. Я полагаю, ваша проблема связана с непониманием этой концепции.

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

10 голосов
/ 07 февраля 2010

У вас есть два файла .c. Они компилируются отдельно . Каждый включает ваш заголовочный файл. Однажды. Каждый получает определение. Они конфликтуют во время ссылки.

Обычное решение:

#ifdef DEFINE_SOMETHING
int something = 0;
#endif

Тогда вы #define DEFINE_SOMETHING в только в одном .c файле.

8 голосов
/ 07 февраля 2010

Защита заголовка останавливает включение файла заголовка несколько раз в одну и ту же единицу перевода (т.е. в один и тот же исходный файл .c). Они не действуют, если вы включаете файл в две или более единиц перевода.

...