Вопрос

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

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

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

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

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

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

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

Это было полезно?

Решение

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

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

Другие советы

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

файл 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 не является защитой заголовка, а позволяет объявлять/определять переменные в зависимости от того, определены ли они.Этот метод позволяет использовать одну копию объявлений/определений.

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

Традиционное решение:

#ifdef DEFINE_SOMETHING
int something = 0;
#endif

Затем вы #define DEFINE_SOMETHING в только один .c-файл.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top