Подтвердить что ты не робот

Ошибка LNK2005, уже определена?

У меня есть 2 файла, A.cpp и B.cpp, в консольном приложении Win32.

Оба 2 файла содержат только следующие 2 строки кода:

#include "stdafx.h"
int k;

При компиляции он выдает ошибку

Error   1   error LNK2005: "int k" ([email protected]@3HA) already defined in A.obj

Я не понимаю, что происходит.

Может кто-нибудь объяснит мне это?

4b9b3361

Ответ 1

Почему эта ошибка?

Вы нарушили одно правило определения и, следовательно, ошибку связывания.

Предлагаемые решения:


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

namespace 
{
    int k;
}

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

хиджры

extern int k;

a.cpp

#include "A.h"
int k = 0;

B.cpp

#include "A.h"

//Use `k` anywhere in the file 

Ответ 2

В настройках проекта добавьте /FORCE:MULTIPLE к параметрам командной строки Linkers.

Из MSDN: "Используйте /FORCE: MULTIPLE для создания выходного файла независимо от того, найдет ли LINK несколько определений для символа".

Ответ 3

Если вы хотите, чтобы оба ссылались на одну и ту же переменную, один из них должен иметь int k;, а другой должен иметь extern int k;

В этой ситуации вы обычно помещаете определение (int k;) в один файл .cpp и помещаете декларацию (extern int k;) в заголовок, который должен быть включен везде, где вам нужен доступ к этой переменной.

Если вы хотите, чтобы каждая k была отдельной переменной, которая имеет одно и то же имя, вы можете отметить ее как static, например: static int k; (во всех файлах или, по крайней мере, все, кроме одного файл). Кроме того, вы можете анонимное пространство имен:

namespace { 
   int k;
};

Опять же, во всех, но не более чем одном из файлов.

В C компилятор обычно не настолько разборчив. В частности, C имеет понятие "предварительное определение", поэтому, если у вас есть что-то вроде int k; дважды (в одном и том же или отдельном исходном файле), каждый будет рассматриваться как предварительное определение, и конфликта не будет между ними. Это может быть немного запутанным, однако, поскольку у вас все еще нет двух определений, которые включают инициализаторы - определение с инициализатором всегда является полным определением, а не предварительным определением. Другими словами, int k = 1;, появляющийся дважды, будет ошибкой, но int k; в одном месте и int k = 1; в другом случае не будет. В этом случае int k; будет рассматриваться как предварительное определение и int k = 1; как определение (и оба относятся к одной и той же переменной).

Ответ 4

Предполагая, что вы хотите, чтобы "k" было другим значением в разных файлах .cpp(следовательно, объявляя их дважды), попробуйте изменить оба файла на

namespace {
    int k;
}

Это гарантирует, что имя "k" однозначно идентифицирует "k" для единиц перевода. Старая версия static int k; устарела.

Если вы хотите, чтобы они указывали на одно и то же значение, измените его на extern int k;.

Ответ 5

Оба файла определяют переменную k как целое число (int).

В результате компоновщик видит две переменные с тем же именем и не уверен, какой из них он должен использовать, если вы когда-либо ссылаетесь на k.

Чтобы исправить это, измените одно из объявлений на:

extern int k;

Это означает: "k - целое число, объявленное здесь, но определенное извне (то есть другой файл)".

Теперь существует только одна переменная k, которая может быть правильно упомянута двумя разными файлами.

Ответ 6

И если вы хотите, чтобы эти единицы перевода делили эту переменную, определите int k; в A.cpp и поместите extern int k; в B.cpp.

Ответ 7

Наличие int k; в файле заголовка вызывает определение символа k в каждой единице перевода, в которую включен этот заголовок, в то время как компоновщик ожидает, что он будет определен только один раз (так называемое нарушение правила определения).

Хотя внушение, связанное с extern, не является неправильным, extern является C-ism и не должен использоваться.

Решение до С++ 17, которое позволяло бы определять переменную в заголовочном файле в нескольких единицах перевода без нарушения ODR, было бы преобразованием в шаблон:

template<typename x_Dummy = void> class
t_HeaderVariableHolder
{
    public: static int s_k;
};

template<typename x_Dummy> int t_HeaderVariableHolder<x_Dummy>::s_k{};

// Getter is necessary to decouple variable storage implementation details from access to it.
inline int & Get_K() noexcept
{
    return t_HeaderVariableHolder<>::s_k;
}

С С++ 17 все становится намного проще, поскольку он позволяет inline переменные:

inline int g_k{};

// Getter is necessary to decouple variable storage implementation details from access to it.
inline int & Get_K() noexcept
{
    return g_k;
}

Ответ 8

Компонент сообщает, что вы указали переменную k несколько раз. Действительно, у вас есть определение в A.cpp и другое в B.cpp. Оба блока компиляции создают соответствующий объектный файл, который использует компоновщик для создания вашей программы. Проблема в том, что в вашем случае компоновщик не знает, какое определение k использовать. В С++ у вас может быть только одно определение одной и той же конструкции (переменная, тип, функция).

Чтобы исправить это, вам нужно решить, какова ваша цель

  • Если вы хотите иметь две переменные, обе названные k, вы можете использовать анонимное пространство имен в обоих файлах .cpp, а затем обратиться к k, как вы сейчас делаете:

.

namespace {
  int k;
}
  • Вы можете переименовать один из k в нечто другое, тем самым избегая дублирования исправления.
  • Если вы хотите иметь только один раз определение k и использовать это в обоих файлах .cpp, вам нужно объявить в одном как extern int k; и оставить его таким же, как и в другом. Это позволит компоновщику использовать одно определение (неизменная версия) в обоих случаях - extern означает, что переменная определена в другом компиляторе.