Мне определили множество характера в заголовке
//header.h
const char* temp[] = {"JeffSter"};
Заголовок, если #defined охранял и имеет #pragma однажды наверху. Если этот заголовок включен в несколько мест, я получаю LNK4006 - константа случайной работы * * временный секретарь, уже определенный в blahblah.obj. Так, у меня есть несколько вопросов об этом
Почему это происходит, если у меня есть охранники на месте? Я думал, что они помешали заголовку быть прочитаны после первого доступа.
Включите охранники, убедитесь, что заголовок включен только один раз в один файл (блок перевода). Для нескольких файлов, включая заголовок, вы хотите, чтобы заголовок был включен в каждый файл.
Определение , в отличие от , в отличие от объявления переменных с внешней связью (глобальными переменными) в файле заголовка, вы можете включить только заголовок в один раз. Если вы включите заголовок в несколько исходных файлов, будут несколько определений переменной, которая не допускается в C ++.
Итак, как вы узнали, это плохое представление о определении переменных в заголовом файле именно причина выше.
Почему многочисленные передачи в этом заголовке также не дают предупреждения LNK4006?
Поскольку они не определяют «глобальные переменные», они только объявления о типах и т. Д. Они не оставляют какое-либо хранение Отказ
Если я добавляю статический перед подписью, я не получаю предупреждение. Каковы последствия этого сделать так.
Когда вы делаете переменную Static
, он имеет статический объем . Объект не виден за пределами блока перевода (файла), в котором он определен. Итак, в простых терминах, если у вас есть:
static int i;
в заголовке, каждый исходный файл, в котором вы включаете заголовок, получат отдельных int
Variable I
, который невидим за пределами исходного файла. Это известно как внутренняя связь .
Есть ли лучший способ сделать это, что позволяет избежать ошибки, но позволяет мне объявить массив в заголовке. Я бы действительно не хотел иметь файл CPP только для определения массива.
Если вы хотите, чтобы массив был одним объектом, видимым из всех ваших файлов C ++, вам следует сделать:
extern int array[SIZE];
в файле заголовка, а затем включить файл заголовка во всех исходных файлах C ++, которые нуждается в переменной массив
. В в одном источника ( .CPP
) файлов необходимо определить массив
:
int array[SIZE];
Вы должны включать в себя заголовок в указанный исходный файл, а также , чтобы добиваться ошибок в связи с разницей в заголовке и исходном файле.
В основном Extern
сообщает компилятору, что « массив
определен где-то, и имеет тип INT
, а размер
Отказ Затем вы на самом деле определяют массив
только один раз. На этапе ссылки все решаются красиво.
Включают охранники, защищающие вас, включая один и тот же заголовок в один и тот же файл несколько раз - но не в том числе в отчетливых файлах.
Что происходит, в том, что линкер видит TEMP
в более чем один объектный файл - вы можете решить, что делая TEMP
статическим или положим его в неназванное пространство имен:
static const char* temp1[] = {"JeffSter"};
// or
namespace {
const char* temp2[] = {"JeffSter"};
}
. Один исходный файл, который определяет TEMP
и просто объявить его как внешний в заголовке:
// temp.cpp:
const char* temp[] = {"JeffSter"};
// header.h:
extern const char* temp[];
... «Джеффстер»}; '.
См. Раздел 6.1 FAQ C FAQ , в разделе «Раздел 6. Массивы и указатели», чтобы цитировать:
6.1: I had the definition char a[6] in one source file, and in another I declared extern char *a. Why didn't it work? A: In one source file you defined an array of characters and in the other you declared a pointer to characters. The declaration extern char *a simply does not match the actual definition. The type pointer-to-type-T is not the same as array-of-type-T. Use extern char a[]. References: ISO Sec. 6.5.4.2; CT&P Sec. 3.3 pp. 33-4, Sec. 4.5 pp. 64-5.
, который является источником проблемы. Соответствовать вашей декларации и определениям. Извините, если это звучит тупо, но я не мог не заметить то, что сказал линкер ...
Надеюсь, это поможет, С уважением, Том.
Заголовочные охранники абсолютно не имеют ничего общего с предотвращением нескольких определений в вашу программу . Целью заголовочных охранников является предотвращение множества включения одного и того же файла заголовка в блок . Блок перевода (.CPP-файл). Другими словами, они существуют, чтобы предотвратить множество определений в в том же исходном файле . И они работают как предназначенные в вашем случае.
Правило, которое регулирует проблемы с множественным определением в C ++, называется одним правилом определения (ODR). ODR определяется по-разному для различных видов сущностей. Например, типы могут иметь несколько идентичных определений в программе. Они могут (и большинство всегда имеют ), определяются в каждом блоке перевода, где они используются. Вот почему ваше определение Enum не приводит к ошибке.
Объекты с внешним соединением - это совершенно другая история. Они должны быть определены в одном и только один блок перевода. Вот почему ваше определение TEMP
вызывает ошибку при включении файла заголовка в несколько блоков перевода. Включите охранники, не могут предотвратить эту ошибку. Просто не определяйте объекты с внешним связью в заголовках файлах.
Добавление Static
Вы даете свой объект внутреннюю связь . Это сделает ошибку исчезнуть, так как теперь она прекрасно в порядке с точки зрения ODR. Но это определит независимый объект TEMP
в каждом блоке перевода, в который включен ваш файл заголовка. Для достижения того же эффекта вы также можете сделать
Const Char * Const Temp [] = {"Джеффстер"};
С Const
объекты в C ++ имеют внутреннюю связь по умолчанию.
Это зависит от того, нужен ли вам объект с внешним соединением (I.E. One для всей программы) или объектом с внутренним соединением (уникальным для каждого блока перевода). Если вам нужен последний, используйте Static
и / или дополнительный const
(если это работает для вас), как показано выше.
Если вам нужна прежняя (внешняя связь), вы должны поместить не определение декларации в заголовочный файл
Extern Const Char * Temp [];
и переместите определение в один и только один файл .CPP
Char * Const Temp [] = {"Джеффстер"};
Вышеуказанная декларация в заголовом файле будет работать в большинстве целей. Однако он объявляет TEMP
как массив неизвестного размера - неполный тип. Если вы хотите объявить его как массив известных размеров, вы должны указать размер вручную
Extern Const Char * Temp [1];
И не забудьте сохранить его в синхронизации между декларацией и определением.