본문 바로가기
C++/기초

C++ 기초 : 정적 변수와 외부 변수

글: 시플마 2024. 3. 29.

어떤 파일에서도 사용할 수 있는 전역 변수를 만드려고 합니다.

그러나 각 파일에 전역 변수를 선언하면 링크 과정에서 

중복 정의 문제가 발생하고, 한 파일에만 선언해서 사용하자니

다른 파일에서 전역 변수를 인식하지 못하는 문제가 발생합니다.

 

이번에는 정적 변수를 통해 이 문제를 해결해 보죠.

정적 변수는 선언된 지역(파일이나 함수)에서만 사용 가능합니다.

정적 변수로 선언하려면 앞에 'static'이라는 키워드를 붙입니다.

 

 

예시를 봅시다.

 

main 함수가 있는 파일에

정적 변수 'global'을 선언하고 0으로 초기화했습니다.

이후 global에 1을 대입합니다.

 

그리고 Add 함수의 정의가 있는 파일에도

정적 변수 'global'을 선언하고 0으로 초기화했습니다.

이후 global에 10을 대입합니다.

 

그 다음에 실행해 보면

 

같은 이름의 변수를 선언하고 사용했음에도

오류가 발생하지 않는 것을 확인할 수 있습니다.

 

 

정적 변수는 선언된 곳 말고는 움직이지 않습니다.

main.cpp에서 "global = 1;" 코드를 만나면

main.cpp에서 선언된 global을 의미하고

func.cpp에서 "global = 10;" 코드를 만나면

func .cpp에서 선언된 global을 의미합니다.

 

즉 main.cpp의 global이라는 변수 따로,

func.cpp의 global이라는 변수 따로 인식하는 것이죠.

(정적 변수도 지역 변수처럼 데이터 영역에 위치하긴 합니다.)

 

 

정말 따로 인식하는지 확인하기 위해 

 

위와 같이

func.cpp 파일에  global에 10을 대입하고

global의 값을 출력하는 코드를,

 

 

 

 

main.cpp 파일에 global에 10을 대입하고

global의 값을 출력하는 코드를 추가했습니다.

 

이후 main.cpp에서 Add 함수를 호출하죠.

Add 함수가 호출되면서 func.cpp 파일의 

내용이 실행될 것입니다.

 

 

결과를 봅시다.

 

각 파일에 있는 global이라는 같은 이름을 가진 

정적 변수의 값이 다른 것이 보이시나요?

 

 

 

 

위 그림처럼 따로 인식하기 때문에

링크 과정에서

"야, global이라는 이름의 변수가 두 개야.

global에 1을 대입하라는데 둘 중 어떤 거에 대입하라는 건데?"

 

"야, global이라는 이름의 변수가 두 개야.

global에 10을 대입하라는데 둘 중 어떤 거에 대입하라는 건데?"

라는 중복 정의 오류가 발생하지 않는 것이죠.

 

 


 

 

 

또한 정적 변수를 함수 안에 선언하면

정적 변수가 함수 안에서만

활동하도록 제한할 수도 있습니다.

 

아래 코드를 봅시다.

 

g_iStatic가 Test 함수 안에서 선언되었으므로

main 함수에서 인식할 수 없는 것이 확인됩니다.

 

 

오류를 수정하고 다시 코드를 봅시다.

 

Test 함수를 만들었습니다.

이 함수는 호출될 때마다

int형 정적 변수 g_iStatic의 값을

올리고 이 값을 반환하는 함수입니다.

 

그리고 이 반환된 값을 담고 출력하기 위해 

int형 변수 iCount를 선언하였습니다. 

 

Test 함수를 5번 호출하고 마지막에

iCount에 반환된 값을 담은 후

이 값을 출력합니다.

 

실행해 보니 5가 출력되네요.

 

5번 호출했고 그때마다

정적 변수 g_iStatic의 값을 1 올렸기 때문이겠죠?

 

비록 g_iStatic가 Test 함수 안에 선언되었더라도

결국 정적 변수이기 때문에 g_iStatic은

Stack 영역이 아닌, Data 영역에 할당됩니다.

 

그래서 Test 함수가 레지스터에

값을 반환하면서 소멸되도

정적 변수인 g_iStatic은 Data 영역에 

그대로 남아 있기 때문에 레지스터에서

반환된 값을 받아 저장할 수 있습니다.

 

 

여기서 주의할 점은 

Test 함수가 호출될 때 가장 먼저 실행되는

명령이 g_iStatic를 선언하고 초기화하는 명령입니다.

 

그래서 Test 함수가 호출될 때마다

g_iStatic가 다시 선언되고 값이 초기화된다고 생각할 수 있는데,

 

함수 내에 선언된 정적 변수는 한 번 초기화되면

다음부터는 초기화 구문을 실행하지 않습니다.

 

이는 어셈블리어를 확인해 보면 나오는데

조건 처리가 되어 있어 한 번 초기화하면

초기화 구문을 건너뛰게 되어 있습니다.

 

 


 

 

근데 위 함수를 보면 정적 변수 대신

전역 변수로 사용해도 될 것 같지 않나요?

 

아래처럼 말이죠.

 

정적 변수를 빼고 전역 변수로

다시 넣었습니다.

 

실행해 보면 결괏값도 같습니다.

 

그럼 여기서 정적 변수를

사용했을 때 좋은 점은 무엇일까요?

 

 

아래 같은 상황이 발생했다고 생각해 봅시다.

 

같이 협업하는 프로그래머가

global이라는 함수가 어떤 용도인지

파악하지 않고 10000을 대입했습니다.

의도한 대로라면 5가 나와야 하는데 

아예 다른 값이 나왔습니다.

 

이렇게 협업자가 실수하는 경우가 아니더라도

프로그램이 복잡해지면 코드가 길어지기 때문에

코드를 작성한 본인도 실수할 수 있습니다.

 

 

실수할 여지 자체를 만들지 않기 위해 

정적 변수를 사용할 수 있습니다.

 

애초에 Test 함수 밖에서 이상한 값을

대입하려고 해도 오류가 발생해서 넣을 수 없기 때문에

실수를 방지할 수 있습니다.

 


 

 

 

변수 하나를 모든 파일에서 사용하고 싶어

전역 변수를 사용했더니 문제가 발생했고,

이를 위해 정적 변수로 문제를 해결했습니다.

 

근데 잘 생각해 보면 해결했다고 보기 어렵죠.

 

정적 변수를 사용하니 오류가 발생하지는 않았지만

사실 이름만 같을 뿐 파일마다 따로 작동하여

다른 값을 갖고 있으니,

"모든 파일에서 값을 공유하는 하나의 변수를 만들자."는 

목표에 도달하지 못했습니다.

 

 

 

이러한 목표를 달성하려면

외부 변수(extern)을 사용해야 합니다.

외부 변수로 선언하려면 앞에 'extern'이라는 키워드를 붙입니다.

 

일단 'common'이라는 이름의

헤더 파일을 하나 만들어서 진행해 볼까요?

 

그리고 common.h 파일에

int형 외부 변수 g_iExtern를 선언하고 0으로 초기화합시다.

 

그 다음 이 변수를 사용할 func.cpp와 main.cpp 파일에 

common.h 파일을 include 지시문을 이용해 넣습니다.

 

 

근데 실행해 보니 오류가 발생합니다.

 

외부 변수 g_iExtern가 이미 정의되어 있다고 합니다.

즉 func.cpp에도, main.cpp에도 변수 g_iExtern가 있어

오류가 발생하는 것입니다.

 

 

외부 변수(extern)을 사용하려면 초기화를 하면 안됩니다.

 

아래 코드처럼

 

일단 g_iExtern이라는 변수가 있다는 것만 

컴파일러가 컴파일 과정에서 알게 해줍시다.

 

 

g_iExtern이라는 변수가 있다는 것을 알려줬으니

func.cpp로 가서

Add 함수를 호출하면 g_iExtern의 값을 출력하는 코드를 넣습니다.

 

 

 

그 다음 main.cpp로 가서

g_iExtern에 1000을 대입하는 코드를 넣어 보겠습니다.

 

 

근데 또 오류가 발생하네요.

오류 목록을 자세히 살펴봅시다.

 

코드가 LNK로 시작하므로 링크 과정에서 오류가 

발생했음을 알 수 있습니다.

 

초기화를 하지 않고 g_iExtern이라는 변수가

있다는 것만 알게 해줬기 때문에 컴파일 과정은

문제없이 넘어갔습니다.

 

그러나 func.cpp과 main.cpp 파일이 링크 과정에서 말하는 것이죠.

 

"야! g_iExtern 변수 있다고 해서 컴파일까지는 했는데

링크해서 찾아봤더니 실체가 없는데?"

 

 

 

외부 변수를 처음 만들 때 초기화하지 않아야

컴파일 과정에서 오류가 발생하지 않고

이후 어떤 파일에서든 초기화를 해주어야

링크 과정에서도 오류가 발생하지 않습니다.

 

Test.cpp라는 파일을 만들어 

 

외부 변수로 사용할 g_iExtern의 값을 초기화합시다.

 

 

그리고 실행해 보면

 

외부 변수 g_iExtern에 1000이 대입되고 

Add 함수가 호출되면서

g_iExtern의 값이 출력되는 것까지

잘 실행되는 것을 확인할 수 있습니다.

 

 

 

 

강의 출처 : https://www.youtube.com/watch?v=PFc4g8mxOiI&list=PL4SIC1d_ab-aOxWPucn31NHkQvNPHK1D1&pp=iAQB


 

'C++ > 기초' 카테고리의 다른 글

C++ 기초 : 포인터  (0) 2024.03.29
C++ 기초 : 운영체제  (0) 2024.03.29
C++ 기초 : 분할 구현의 문제점  (0) 2024.03.22
C++ 기초 : 분할 구현  (0) 2024.03.06
C++ 기초 : 지역 변수 / 전역 변수  (0) 2024.03.05