code

오류 LNK2005, 이미 정의 되었습니까?

codestyles 2020. 11. 19. 08:15
반응형

오류 LNK2005, 이미 정의 되었습니까?


Win32 콘솔 응용 프로그램에 A.cpp 및 B.cpp 파일이 있습니다.

두 파일 모두 다음 두 줄의 코드 만 포함합니다.

#include "stdafx.h"
int k;

컴파일 할 때 오류가 발생합니다.

Error   1   error LNK2005: "int k" (?a@@3HA) already defined in A.obj

나는 무슨 일이 일어나고 있는지 이해하지 못한다.

누군가 나에게 이것을 설명해 주시겠습니까?


왜이 오류입니까?

하나의 정의 규칙을 위반하여 연결 오류가 발생했습니다.

제안 솔루션 :


두 개의 cpp 파일에 동일한 이름의 변수가 필요한 경우 오류를 방지하기 위해 Nameless namespace (Anonymous Namespace)를 사용해야합니다.

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 

프로젝트 설정 /FORCE:MULTIPLE에서 링커의 명령 줄 옵션에 추가 합니다 .

에서 MSDN : "사용 / FORCE :. 기호에 대한 출력 파일 링크 발견 여부를 하나 이상의 정의를 작성하기 위해 여러"


둘 다 동일한 변수를 참조하도록하려면 둘 중 하나에가 있어야 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;(둘 다 동일한 변수를 참조 함).


'k'가 다른 .cpp 파일에서 다른 값이되기를 원한다고 가정하면 (따라서 두 번 선언) 두 파일을 다음과 같이 변경해보십시오.

namespace {
    int k;
}

이렇게하면 'k'라는 이름이 번역 단위 전체에서 'k'를 고유하게 식별합니다. 이전 버전 static int k;은 더 이상 사용되지 않습니다.

동일한 값을 가리 키도록하려면 1을로 변경하십시오 extern int k;.


두 파일 모두 변수 k를 정수 ( int) 정의합니다 .

결과적으로 링커는 이름이 같은 두 개의 변수를보고를 참조 할 경우 어떤 변수를 사용해야하는지 확실하지 k않습니다.

이 문제를 해결하려면 선언 중 하나다음으로 변경 하십시오.

extern int k;

, "k는 여기에 선언 된 정수이지만 외부 적으로 정의됩니다 (예 : 다른 파일)."

Now there is only one variable k, that can be properly referred to by two different files.


And if you want these translation units to share this variable, define int k; in A.cpp and put extern int k; in B.cpp.


Presence of int k; in the header file causes symbol k to be defined within each translation unit this header is included to while linker expects it to be defined only once (aka One Definition Rule Violation).

While suggestion involving extern are not wrong, extern is a C-ism and should not be used.

Pre C++17 solution that would allow variable in header file to be defined in multiple translation units without causing ODR violation would be conversion to template:

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;
}

With C++17 things become much simpler as it allows inline variables:

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;
}

The linker tells you that you have the variable k defined multiple times. Indeed, you have a definition in A.cpp and another in B.cpp. Both compilation units produce a corresponding object file that the linker uses to create your program. The problem is that in your case the linker does not know whic definition of k to use. In C++ you can have only one defintion of the same construct (variable, type, function).

To fix it, you will have to decide what your goal is

  • If you want to have two variables, both named k, you can use an anonymous namespace in both .cpp files, then refer to k as you are doing now:

.

namespace {
  int k;
}
  • You can rename one of the ks to something else, thus avoiding the duplicate defintion.
  • If you want to have only once definition of k and use that in both .cpp files, you need to declare in one as extern int k;, and leave it as it is in the other. This will tell the linker to use the one definition (the unchanged version) in both cases -- extern implies that the variable is defined in another compilation unit.

참고URL : https://stackoverflow.com/questions/10046485/error-lnk2005-already-defined

반응형