인프런 커뮤니티 질문&답변

홍길동님의 프로필 이미지
홍길동

작성한 질문수

홍정모의 따라하며 배우는 C++

4.2 전역 변수, 정적 변수, 내부 연결, 외부 연결

(42:20)코딩에 문제가 없어 보이는데 빌드가 안됩니다.

작성

·

1.2K

3

//header

//main cpp

//test cpp

// problem (영상 32:20와 동일함)

LNK2005와 LNK1169입니다.

영상 (32:20)과 같은 문제가 발생했습니다.

추가된 파일도 없으며, (43:20)의 과정을 그대로 따라해보았는데 발생했습니다.

반복된 함수도 없는 것으로 보아 코딩에 문제점도 여전히 찾지 못하고 있습니다.

답변자님 매번 감사합니다.

답변 3

21

Hearder.h 헤더파일에서 extern const int a(123); 하셨기 때문에 발생한 오류입니다.

오류가 나지 않으려면 1️⃣ extern을 빼시거나 2️⃣ 혹은, Header.h 에서는 extern const int a; 이렇게 선언만 해두시고 Header.cpp 이런 cpp 파일을 만들어서 거기서 초기화를 하셔야 합니다. 해당 43:20 실행 결과를 내신 교수님의 MyConstant.h 헤더 파일에서도 extern 을 붙이지 않으셨습니다! (39:00 참고해주세요) 43:20 실행 결과를 내셨을 때 사용된 예제는 Hearder.h 헤더파일에서 extern 을 사용하지 않으셨을 때로 코딩하신 후 내신 결과였습니다. 즉, 교수님께서 헤더파일로부터 받은 변수들을 메모리 공유하지 않고 사본으로 생성했을 때를 보여주시기 위해서 예시로 든 부분이셨어요! 

질문자님 코드의 링킹 에러 문제를 해결하려면 두 가지 방법이 있습니다.

1️⃣ (제가 앞에서 말씀드린 방법인) Hearder.h 헤더파일에서 extern 을 빼고 그냥 const int a(123); 만 선언하는 방법

👉 이 방법의 실행 결과가 42:55 입니다.

👉 이 경우엔, 이 헤더파일을 포함하는 main.cpp 와 test.cpp 에서 Hearder.h 헤더파일의 전역 변수 a 의 메모리를 공유하는게 아니라 그냥 사본으로서서 복사 받았을 뿐입니다. (42:55 참고하시면 main.cpp와 test.cpp의 Constants::pi 주소가 서로 다른 별개의 변수인거 확인할 수 있습니다)

👉 그래도 딱히 생기는 문제는 없습니다! 링킹이 잘 됩니다. 다만, 강의에서 교수님이 말씀하신것 처럼 예를 들어 프로그램 규모가 커서 cpp 파일 개수가 막 1000개가 넘어간다면, 중력 가속도라던지 파이라던지 등등 이런 헤더파일의 전역 변수들을 여러 파일들에서 include 하여 사용하면 1000개 넘는 사본이 생기는 셈이라 이 방법은 프로그램 규모가 클 경우 메모리 낭비가 심합니다. 즉 메모리 1000개를 할당받는 셈이기 때문이에요. 따라서 프로그램 규모가 크고 수 많은 cpp 파일에 포함시킬 헤더 파일이라면 extern 을 사용하여 전역 변수 단 하나의 메모리를 전체 파일들에서 공유하는 것을 권장합니다.

2️⃣ Hearder.h 헤더파일에서 extern 을 붙이되, extern const int a; 이렇게 선언만해두고 초기화는 헤더 파일에서 하지 않고 Header.cpp 파일을 만들어 이 곳에서 extern xonst int a(123); 초기화하는 방법

👉 이 방법의 실행 결과가 46:00 입니다. (MyContants.h 헤더 파일에서는 선언만 하시고 초기화는 MyConstants.cpp 에서 해주신 결과에요)

👉 먼저 extern const int a;extern const int a(123); 의 차이를 아셔야 합니다. extern const int a; 는 컴파일러에게 "나는 다른 파일에 있는 a 변수의 메모리를 공유할거야. 다른 파일에 있는 그 a 변수를 쓸거야" 라고 알려주는 역할만 할 뿐, 실제 선언처럼 메모리 공간을 확보하지 않습니다. 즉, a라는 변수를 새롭게 만들라는 문장이 아닙니다. 이와 달리 extern const int a(123); 는 실제로 a 라는 변수의 메모리 저장공간을 확보하고 123 값을 넣어줍니다. 즉, a라는 변수를 새롭게 선언하고 정의한 것입니다. 덧붙여서 a 변수가 여러 파일들에서 메모리 공유되는 방식으로 쓰일거라면 초기화는 단 한군데서만 이루어져야 합니다. 메모리 공간을 확보하고 123 값을 넣어주는 일은 그냥 이 a 변수를 사용하는 파일들 중 하나에서만 이루어지면 됩니다. (이 부분도 강의에서 설명해 주신 것으로 알고 있는데 제가 정확히 어느 부분에서 설명해주신건지 잘 못찾겠네요 ㅠㅠ)

👉 동일한 변수를 같은 범위 내에서 두 번 정의하는 것은 오류가 나죠. 또한 헤더파일을 include 할 때는 그 헤더 파일의 전체 코드들을 "복사"해오는 식으로 작동이 되죠. 질문자님께서 링킹 에러가 나신 궁극적인 이유는 헤더 파일에서 이렇게 a 변수를 "정의"해주셨기 때문에 이 헤더파일을 포함하는 main.cpp 와 test.cpp 에서 각각  extern const int a(123); 를 실행하게 된 것이나 마찬가지이기 때문입니다. 즉, 헤더파일로부터 이 코드를 복사해와서 를 각각 실행하게 된 것인데, extern을 붙였으니 a 변수는 단 하나의 메모리로 여러 파일에서 공유가 되야되는 변수인데 두 번이나 메모리 확보를 해주었기 때문에 에러가 발생한 것입니다. 즉 동일한 a 변수를 두 번이나 정의해준 것이나 똑같아요. 

// Header.h

// main.cpp

// test.cpp

이렇게 main.cpp와 test.cpp 는 빈 코드로 냅두고 오직 "Header.h"를 include 하기만 해도 질문자님과 똑같은 에러가 난다는 것을 확인할 수 있을겁니다. 컴파일시 "Header.h"로부터 두 main.cpp 와 test.cpp 가 "Header.h" 내의 모든 코드들을 복사해오는 과정을 거치는데, extern const int a(123); 이 문장이 두 cpp 파일에 복사되어 공유 되어야 할 a 변수가 두 번이나 메모리 정의가 되었기 때문에 발생한 에러입니다. 한 공간안에 const int a = 123; 두 번 선언하면 에러 나는 것과 비슷해요!

// Header.h

// Header.cpp

이렇게 헤더 파일에선 컴파일러에게 외부에서 메모리 정의된 a 라는 변수를 공유할거야 라는 것만 알려주고 메모리 정의 및 초기화는 Header.cpp 를 만들어 이 곳에서 진행하면 문제가 해결 됩니다. main.cpp와 test.cpp 에서는 extern const int a; 를 각각 헤더에서 복사 받아 실행하는데 메모리가 두 번 정의되는 것 없이 그냥 외부에서 메모리 정의된 그 a 변수의 메모리를 공유할게요 라고 선언하는 의미가 되기 때문에 문제가 발생하지않게 됩니다. 그저 Header.cpp 에서 메모리 정의한 그 a 변수에 접근해서 사용할 수 있게 되요! extern 전역 변수는 메모리가 한 파일에서만 정의되면 되기 때문에 이런식으로 해도 문제 없습니다. 따라서 반드시 헤더파일에 extern 변수를 정의할 것이라면 초기화는 꼭!!! 헤더파일이 아닌 다른 cpp 파일에서 해주셔야 합니다. (+덧붙여서 이렇게 Header.cpp 파일에서 초기화 해주실 때 extern 빼고 const int a(123); 만 해줘도 문제 없겠네요! Header.cpp도 Header.h 로부터 extern const int a; 를 복사 받게 되니까요)

이해가 잘 되셨으면 좋겠네요 ㅎㅎㅎ

정성글에 감탄하고, 설명에 감탄하고 갑니다. 감사합니다.

설명이 감동적이네요. 잘 보고 갑니다.

감사합니다.

0

감사합니다...바로 이해 해버렸네요

0

홍길동님의 프로필 이미지
홍길동
질문자

친절하고 구체적인 답변 너무너무 감사드립니다.

최고의 답변이에요! 설명해주신 말씀, 모든 것이 이해가 갔어요.

본 챕터에서 고민하는 모든 이들에게도 도움이 될 답변이에요. 알려주셔서 감사합니다~!!

홍길동님의 프로필 이미지
홍길동

작성한 질문수

질문하기