Как избежать ошибки компоновщика LNK2005 для переменных, определенных в заголовочном файле? - PullRequest
6 голосов
/ 07 апреля 2011

У меня есть 3 файла cpp, которые выглядят следующим образом

#include "Variables.h"
void AppMain() {
    //Stuff...
}

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

1>OnTimer.obj : error LNK2005: "int slider" (?slider@@3HA) already defined in AppMain.obj

Почему это так?

Ответы [ 7 ]

16 голосов
/ 07 апреля 2011

Имейте в виду, что #include примерно похоже на вырезание и вставку включенного файла в исходный файл, который его включает (это грубая аналогия, но вы понимаете, в чем дело).Это означает, что если у вас есть:

int x;  // or "slider" or whatever vars are conflicting

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

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

в Variables.h:

extern int x;

в SomeSourceFile.cpp

int x;

Конечно, я бы рекомендовал не использовать глобальные переменные, но если вы должны их использовать, это предотвратит конфликт.

3 голосов
/ 07 апреля 2011

Это потому, что компилятор компилирует каждый файл .cpp отдельно, создавая файл .obj для каждого.Похоже, что ваш заголовок имеет что-то вроде:

int slider;

Когда он входит в каждый из ваших трех .cpp файлов, вы получаете три копии переменной int slider, так же, какесли вы объявили это в каждом файле .cpp.Компоновщик жалуется на это, потому что у вас нет трех разных вещей с одним и тем же именем.

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

extern int slider;

Это говориткомпилятор, который где-то есть переменная slider, но, возможно, не здесь, и позволяет компоновщику выяснить это.Затем в один .cpp файл:

int slider;

дает компоновщику одну фактическую переменную для ссылки.

3 голосов
/ 07 апреля 2011

Потому что "слайдер int" уже определен в другом файле?Проверьте, есть ли у вас средства защиты заголовков ...

#ifndef _VARIABLES_H_
#define _VARIABLES_H_

int slider;

#endif

Если это в нескольких единицах перевода и вы хотите, чтобы переменные были разными (то есть не глобальными), то, возможно, объявите их в анонимном пространстве имен:

namespace {
    int slider;
}

Если вы хотите, чтобы они были глобальными, обратитесь к решению Джеймса.

1 голос
/ 25 апреля 2015

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

namespace Vert
{
   static int i;
}

Я попробовал extern, и в моей ситуации это, похоже, не решило проблему.

1 голос
/ 07 апреля 2011

То, что происходит, - то, что каждой из переменных из Variables.h дают глобальную область видимости для каждого из отдельных файлов c.Когда компоновщик компилирует все файлы c, он видит несколько переменных с одним и тем же именем.

Если вы хотите использовать переменные из файла заголовка в качестве глобальных переменных, вам придется использовать ключевое слово "extern"перед всеми ними и в основном файле не используйте ключевое слово extern.

main c:

int n_MyVar;

другие файлы:

extern int n_MyVar;

Вы можете создать два файла Variables.h и EVariables.h или просто объявить переменные в файле main.cpp.

Гораздо лучший способ сделать это - создать класс переменных и передать ссылку накласс.

0 голосов
/ 27 апреля 2018

У меня тоже была эта ошибка, хотя я работаю с внешними определениями. Проблема была также в инициализации переменных во внешних определениях:

ID3D11VertexShader*         g_pVertexShader = nullptr;
...
extern ID3D11VertexShader*  g_pVertexShader = nullptr;  // here's the problem 

=> ошибка

ID3D11VertexShader*         g_pVertexShader = nullptr;
...
extern ID3D11VertexShader*  g_pVertexShader;           // without initializing  

=> нет ошибок, проблема решена

0 голосов
/ 02 сентября 2013

Этой ошибки связывания также можно избежать, если переменные, включенные несколько раз через "Variables.h", объявлены как const.

...