본문 바로가기
Study/C++

헤더파일에 전역변수 선언관련

by 뿡뿡대마왕 2014. 6. 18.
반응형

출처:

http://blog.naver.com/PostView.nhn?blogId=phh0606c&logNo=10174041285&categoryNo=8&parentCategoryNo=0&viewDate=&currentPage=1&postListTopCurrentPage=1&userTopListOpen=true&userTopListCount=5&userTopListManageOpen=false&userTopListCurrentPage=1


가끔 생각없이 헤더파일에 전역변수 선언하고 

헤더파일에 있는 함수 쓰려고 다른 cpp에서 include하면 에러나는데

이때 머리가 띵해지는 경우가 있다...-_-;

멍청한 짓거리는 이제 그만.ㅠㅠ


1) 어려운 일인가?

- 어렵다. 그러니까 일반 전역 변수처럼 그냥 선언만 해서는 안된다.  

 

2) 왜 ?

- C/c++ 의 header file은 똑똑하지 않다. header file은 사실 다른 거 없이 include 하게 되면 그냥 코드를 복사해서 붙여 넣는 것과 마찬가지다. 따라서 headerfile을 너무 남발해서 불러오면 정의 됐던 것을 또 다시 정의하게 되는 일이 생긴다. 함수 같은 경우에는 선언과 정의가 분리 되어 있기 때문에(같은 선언은 여러 번 해도 상관없다) 선언한 내용을 몇 번을 불러도 상관없다. 그래서 헤더 파일엔 보통 선언만 들어가게 된다. 하지만 변수 같은 경우에는 선언과 동시에 default 값으로 정의도 돼 버리기 때문에(쓰레기값) 여러 번 선언 할 수가 없게 된다. 따라서 헤더 파일에 일반적으로 전역 변수를 선언만 하더라도 헤더 파일을 부를 때 마다 중복된 정의가 일어나기 때문에 multiple definition of "변수 이름" 이라는 에러를 만나게 된다.  

 

3) 해결책은?

-  extern 이 해결 방법이다.  c/c++ 에서 extern 이란 이런 의미가 있다. " extern 이라고 붙어 있는걸 보니 이놈은 어딘가 다른 곳에서 정의가 되어있는 놈이군, 나중에 데리고 와야지~ " 하고 무시해 버린다. 조건은 로컬 변수가 아닌 global 변수여야지 다른 외부에서도 참조가 가능하다. 역시 설명력이 딸리니까 예제를 봐야겠다.

 

해결책 1 . 

//sample.h

#ifndef SAMPLE_H_
#define SAMPLE_H_
class Sample{
public:
    int i;
    Sample(){}
};
extern Sample* sample; 

 

#endif 

//function.h 

#ifndef FUNCTION_H_
#define FUNCTION_H_

void function();
void function2(); 

 

#endif

//sampleFunction.cpp

#include "sample.h"
void function(){
    sample->i ++;

//sampleFunction2.cpp

#include "sample.h"
void function2(){
    sample->i ++;

//main.cpp

#include "sample.h"
#include "function.h"
#include <iostream> 

 

Sample* sample;
int main(){
    sample = new Sample();
    sample->i = 1;
    function();
    function2();
    std::cout << sample->i << std::endl;
}

extern 한 부분이 없으면 multiple definition 에러가 뜬다. 저렇게 작성하면 잘 돌아간다. extern은 외부에서 정의 될 것이고 그 정의는 main.cpp에서 글로버 변수로 한 번 정의 되기 때문이다. (꼭 글로벌 변수여야 한다. 로컬변수는 되지 않는데 메모리 영역의 내용이라 생략) 

 

해결책 2. 

 

//sample.h

#ifndef SAMPLE_H_
#define SAMPLE_H_
class Sample{
public:
    int i;
    Sample(){}
};

 

#ifdef SAMPLE_DEF
#define EXT
#else
#define EXT extern
#endif
EXT Sample* sample;

 

#endif

//main.cpp

#define SAM_DEF<br />#include "sample.h"<br />#include "function.h"<br />#include <iostream><br /><br /><br />int main(){<br />    Sample* sample = new Sample(); // 여기서 처음 선언 한다. <br />    sample->i = 1;<br />    function();<br />    function2();<br />    std::cout << sample->i << std::endl;<br />}

전처리 매크로를 활용해서 해결하는 방법이 있다. 의미는 ifdef SAMPLE_DEF (만약 SAMPLE_DEF 이 정의 되어 있다면), EXT 는 null 이므로 EXT Sample* sample 은 Sample* sample 이 되어 선언과 정의를 하게 된다. 하지만 SAMPLE_DEF 정의 되지 않은 곳에서는 EXT는 extern으로 치환 되기 때문에 정의 되어 있는 sample을 찾아 가게 된다.  

이렇게 처리해줄 경우는 1번 해결책과 달리 헤더파일에서 sample 글로벌 변수를 선언하게 되는 것이다. 1번 경우에는 main에서 선언된 글로벌 변수를 extern을 통해 찾아 간 것이고 2번 경우에는 정의하는 부분이 있는 곳에 SAMPLE_DEF 를 정의 함으로서 sample을 정의하게 되고 정의가 없는 부분에서는 extern을 통해 찾아가도록 하는 차이가 있다.   

 


반응형

댓글