Гвардия заголовка и LNK4006

Мне определили множество характера в заголовке

//header.h
const char* temp[] = {"JeffSter"};

Заголовок, если #defined охранял и имеет #pragma однажды наверху. Если этот заголовок включен в несколько мест, я получаю LNK4006 - константа случайной работы * * временный секретарь, уже определенный в blahblah.obj. Так, у меня есть несколько вопросов об этом

  1. Почему это происходит, если я имею в распоряжении охранников? Я думал, что они препятствовали тому, чтобы заголовок был прочитан в после первого доступа.
  2. Почему делают многочисленные enums в этом заголовке не также дают предупреждения LNK4006?
  3. Если я добавляю статичный перед подписью, я не получаю предупреждение. Каковы последствия выполнения его этот путь.
  4. Есть ли лучший способ сделать это, которое избегает ошибки, но позволяет мне объявить множество в заголовке. Я действительно очень не хотел бы иметь cpp файл только для определения множества.
10
задан Steve 20 January 2010 в 23:02
поделиться

4 ответа

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

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

Определение , в отличие от , в отличие от объявления переменных с внешней связью (глобальными переменными) в файле заголовка, вы можете включить только заголовок в один раз. Если вы включите заголовок в несколько исходных файлов, будут несколько определений переменной, которая не допускается в C ++.

Итак, как вы узнали, это плохое представление о определении переменных в заголовом файле именно причина выше.

Почему многочисленные передачи в этом заголовке также не дают предупреждения LNK4006?

Поскольку они не определяют «глобальные переменные», они только объявления о типах и т. Д. Они не оставляют какое-либо хранение Отказ

Если я добавляю статический перед подписью, я не получаю предупреждение. Каковы последствия этого сделать так.

Когда вы делаете переменную Static , он имеет статический объем . Объект не виден за пределами блока перевода (файла), в котором он определен. Итак, в простых терминах, если у вас есть:

static int i;

в заголовке, каждый исходный файл, в котором вы включаете заголовок, получат отдельных int Variable I , который невидим за пределами исходного файла. Это известно как внутренняя связь .

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

Если вы хотите, чтобы массив был одним объектом, видимым из всех ваших файлов C ++, вам следует сделать:

extern int array[SIZE];

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

int array[SIZE];

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

В основном Extern сообщает компилятору, что « массив определен где-то, и имеет тип INT , а размер Отказ Затем вы на самом деле определяют массив только один раз. На этапе ссылки все решаются красиво.

14
ответ дан 3 December 2019 в 18:33
поделиться

Включают охранники, защищающие вас, включая один и тот же заголовок в один и тот же файл несколько раз - но не в том числе в отчетливых файлах.
Что происходит, в том, что линкер видит 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[];
4
ответ дан 3 December 2019 в 18:33
поделиться

... «Джеффстер»}; '.

См. Раздел 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.

, который является источником проблемы. Соответствовать вашей декларации и определениям. Извините, если это звучит тупо, но я не мог не заметить то, что сказал линкер ...

Надеюсь, это поможет, С уважением, Том.

-1
ответ дан 3 December 2019 в 18:33
поделиться
  1. Заголовочные охранники абсолютно не имеют ничего общего с предотвращением нескольких определений в вашу программу . Целью заголовочных охранников является предотвращение множества включения одного и того же файла заголовка в блок . Блок перевода (.CPP-файл). Другими словами, они существуют, чтобы предотвратить множество определений в в том же исходном файле . И они работают как предназначенные в вашем случае.

  2. Правило, которое регулирует проблемы с множественным определением в C ++, называется одним правилом определения (ODR). ODR определяется по-разному для различных видов сущностей. Например, типы могут иметь несколько идентичных определений в программе. Они могут (и большинство всегда имеют ), определяются в каждом блоке перевода, где они используются. Вот почему ваше определение Enum не приводит к ошибке.

    Объекты с внешним соединением - это совершенно другая история. Они должны быть определены в одном и только один блок перевода. Вот почему ваше определение TEMP вызывает ошибку при включении файла заголовка в несколько блоков перевода. Включите охранники, не могут предотвратить эту ошибку. Просто не определяйте объекты с внешним связью в заголовках файлах.

  3. Добавление Static Вы даете свой объект внутреннюю связь . Это сделает ошибку исчезнуть, так как теперь она прекрасно в порядке с точки зрения ODR. Но это определит независимый объект TEMP в каждом блоке перевода, в который включен ваш файл заголовка. Для достижения того же эффекта вы также можете сделать

     Const Char * Const Temp [] = {"Джеффстер"};
     

    С Const объекты в C ++ имеют внутреннюю связь по умолчанию.

  4. Это зависит от того, нужен ли вам объект с внешним соединением (I.E. One для всей программы) или объектом с внутренним соединением (уникальным для каждого блока перевода). Если вам нужен последний, используйте Static и / или дополнительный const (если это работает для вас), как показано выше.

    Если вам нужна прежняя (внешняя связь), вы должны поместить не определение декларации в заголовочный файл

     Extern Const Char * Temp [];
     

    и переместите определение в один и только один файл .CPP

     Char * Const Temp [] = {"Джеффстер"};
     

    Вышеуказанная декларация в заголовом файле будет работать в большинстве целей. Однако он объявляет TEMP как массив неизвестного размера - неполный тип. Если вы хотите объявить его как массив известных размеров, вы должны указать размер вручную

     Extern Const Char * Temp [1];
     

    И не забудьте сохранить его в синхронизации между декларацией и определением.

4
ответ дан 3 December 2019 в 18:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: