본문 바로가기
C++

[C++] 지역변수, 전역변수, 정적변수, 외부변수

by arirang_ 2023. 2. 23.
더보기

[변수의 종류]

1. 지역변수

2. 전역변수

3. 정적변수(static)

4. 외부변수(extern)

 

[메모리 영역]

1. 스택 영역 

2. 데이터 영역

3. 읽기 전용(코드, ROM)

4. 힙 영역

#include <stdio.h>

ing g_i = 0;    //전역변수, Data 영역- 계속 상주해있는 메모리 영역

int main() {
   // 지역변수

   return 0;
}
더보기

전역변수 - 데이터 영역

 

[Data 영역 특징]

1. 프로그램 시작 시 생성

2. 프로그램 종료 시 해제

 

스택영역과 데이터 영역


분할 구현

- 헤더랑 파일을 분리해서 구현

-func.h와 func.cpp로 파일 분리

#include <stdio.h>

int g_i = 0;

void Test();    //Tset()의 실체가 있다는 것만 알려줌

int main() { 
    
    int a = 0;
    Test();
    Test();
 }
 
 
 void Test(){
 
   ++g_i;           //함수 실제 구현
 }
더보기

※ 에러 : 

- 문법이 틀렸을 때 : 컴파일도 안해줌(C...)

- LINK 단계에서 오류..

 

- func.h

int add(int a, int b);
...

 

- func.cpp

#include "func.h"       //func.h 내용 여기다 복붙하겠다는 의미 (참조)

//int Add(int a, int b);  //func.h에 있던 내용 그대로 가져온다는 의미, #include "func.h"의 의미다

//그리고 여기다가 Add함수 실제 구현
int Add(int a, int b) {
    return a+b;
 }

 

- 이 func.cpp의 기능을 main에서 사용하고 싶다면..?

→ func.h 참조하면 된다!!!

 

main.cpp

#include <stdio.h>

int g_i = 0;

#include "func.h"      //Add함수 사용하고 싶을 때 헤더 참조, func.h 복붙하는 의미
//int Add(int a, int b); 이걸 불러온다는 것과 의미와 같다.

int main() {



  return 0;
}

 

호출해볼 수도 있다 - Link 과정에서 연결됨!!

#include <stdio.h>

int g_i = 0;

#include "func.h"      //Add함수 사용하고 싶을 때 헤더 참조, func.h 복붙하는 의미
//int Add(int a, int b); 이걸 불러온다는 것과 의미와 같다.

int main() {

  int data = Add(10,20);     //Link 과정에서 다 연결이 된다!

  return 0;
}

- main에서 헤더를 참조하면 구현된 함수 다 가져다가 쓸 수 있다
(Link 과정에서 다 문제없이 연결이 될 것이다)

 

 

- 분리를 하면 정리가 된다!

더보기

func.h

func.cpp

main.cpp

func.h 

- 선언파트 ("이런 함수가 있다"라고만 알려주는 것, 함수 소개 느낌..?!)

int Add(int a, int b);       //선언
int Sub(int a, int b);
int Mul(int a, int b);

 

func.cpp - 함수 구현 몰아서 해놓기

#include "func.h"

int Add(int a, int b){
   return a+b;
}

int Sub(int a, int b){
   return a-b;
}

int Mul(int a, int b){
   return a*b;
}

 

main.cpp - 함수 기능이 필요한 파일에서 헤더만 참조하면 구현된 함수를 사용할 수 있다
(함수구현이 어디에 되어있는지 상관없음, 참조만 하면 갖다 쓸 수 있음)

#include <stdio.h>

int g_i = 0;

#include "func.h"      //구현된 함수 불러다가 사용 가능


int main() {

  int data = Add(10,20);     //Link 과정에서 다 연결이 된다!
  int data2 = Sub(20,10);    //구현된 함수 불러다가 사용 가능
  int data3 = Mul(10,20);

  return 0;
}

#include는 그냥 복사 붙여넣기다

 

- 유사하거나 관련있는 함수들 한쪽 파일에 몰아넣고 관리가 가능하다! (예시 수학관련 사칙연산, 몬스터 관련 기능)

 

- 헤더와 파일을 구분해서 사용하는 이유

→ 손쉽게 관리하기 위해서! 유지 보수에 좋으니까! (코드 재사용!!)

 

but 속도저하가 있긴함..

 

그리고 헤더와 파일을 분리해서 사용하면 문제점이 전역 변수에 문제점이 발생한다!!


분할 구현의 문제점

- (1) 함수 구현을 헤더에다가 하지 않는 이유 
(왜 굳이 헤더를 만들고 파일을 만들어서 분리할까? 헤더에 함수를 다 구현해 놓으면 파일 하나 더 안만들어도 되잖아?)

- 헤더와 파일을 분리하는 이유는 코드의 재사용성을 높이기 위함이다.

  그런데 헤더에다가 함수를 다 구현에 놓으면 #include될 때마다 함수 코드가 그 파일에 복붙될 것이다. 

  그렇게 복붙되서 들어올꺼면 굳이 파일을 헤더를 만들 필요도 없지..

낭비 그 자체야..그 자체..^^ 일을 2번 하는 느낌..

- 또한 합쳐질 때 파일마다 Add 함수가 다 들어가 있어서 똑같은 Add 함수가 3개 존재하게 되고 똑같은 이름의 함수가 존재하므로 문제가 발생한다. 따라서 헤더 파일에는 선언만 해줘야 하고 따로 함수 구현 파일을 만들어서 LINK 해줘야 하는 것!

그러면 Add라는 함수는 함수 파일에 하나만 만들어지고 참조될 때마다 LINK되서 아무 문제가 발생하지 않고 잘~연결됨ㅎ

 

 

- (2) 헤더와 파일을 분리하니까 내가 선언한 전역변수를 다른쪽 파일에서 문법적으로 인식시키기가 힘들다.

(컴파일에서는 문제가 되지 않는다. 각각 파일에서 진행하는거니까. 빌드할 때 문제가 된다. 파일들을 합쳐서 LINK라는 과정을 거칠 때 문제가 발생함, 데이터 영역에 같은 이름의 전역변수 존재..)

다른 파일에서 내가 선언한 전역변수에 접근하도록 어떻게 해야할까...?

→ 정적변수 외부변수로 이를 해결할 수 있다!

 

정적변수

- 키워드 : static 

- 정적변수는 데이터 영역을 사용함 

- 정적이다 ↔ 동적이다(다이나믹)

- 정적변수 - 선언된 곳에서만 콕 박혀서 선언된 곳에서만 있는 것
(내가 생성한 위치에 콕 박혀서 꼼짝 안하고 있는 이미지 떠올리면 됨) - 자기가 선언된 파일에서 꼼짝달싹 안함

- 전역변수에서 발생하는 문제가 static 변수에서는 발생하지 않음!

- 전역변수인데 똑같은게 여러개 있는 것은 문제가 되지만, 

main쪽에서 iStatic이라고 하면 iStatic은 main쪽 것이고, (main에서 안움직이는애니까)

func.cpp쪽에서 iStatic이라고 하면은 iStatic은 func.cpp의 것이다.

왜냐면 각자 파일 전용으로 만들어진 애들이니까 (그 파일이랑 같이 다니는 느낌)

- 같은 이름을 가진 변수더라도 구별이 된다!!!!!! (중복 문제 발생 X)

  자기가 선언된 위치에서만 동작을 한다!!!!!!!!!!!

같은 변수의 이름을 가진 static 변수
static은 자기가 선언된 위치에서만 동작하기 때문에 같은 이름을 가진 변수더라도 문제가 되지 않는다

 

- 함수 안에서 static 변수가 선언된 경우 해당 함수 내에서만  동작을 한다

Test() 함수 지역에서 움직이지 않는다.

근데 정적변수이기 때문에 메모리 영역은 스택 영역을 사용하지 않고 데이터 영역을 사용한다.

(함수가 호출될 때 생성되거나 해제되지 않고 계속 유지(존재)되고 있지만 함수 내에서만 사용 가능하다.)

#include <stdio.h>

static int iStatic = 0; 

void Test() {
   
   static int i =0;

}


int main() {

  iStatic = 100;         //가능
  i = 50;                //불가능

  return 0;
}

 

변수를 상시 유지시키고 싶으면 전역변수를 사용하면 되지만,

정적변수는 다른 곳에서는 사용하지 못한다는 특징이 더 존재한다

즉 정적 변수는 전역변수와 달리 다른 곳에서 그 변수를 사용하지 못한다는 것이다! (각자 그 지역 전용)

#include <stdio.h>


int Test() {
   
   static int i =0;      //함수가 호출될 때마다 i값이 0이 되는 것이 아니다. 초기화는 1번만 진행한다.
   ++i;
   
   retrun i;
}


int main() {
   Test();
   Test();
   Test();
   Test();
   int iCall = Test();
   
   printf("반복된 i 횟수: %d" , iCall);      //따라서 i의 결과값은 5가 나온다. 
}

 

 

- 모든 파일이 공통적으로 접근할 수 있는데 common 헤더파일

- common이라는 헤더파일을 만들고 정적변수의 위치를 common.h로 옮겨보자 

 

common.h - 정적변수 선언

static int g_iStatic = 0;

 

main쪽에서 common 참조

#include <stdio.h>
#include "func.h"
#include "common.h"       //common 참조(복붙)



int main() {
   
   return 0;
}

 

func.cpp에서도 참조

#include "func.h"
#include "common.h"

int Add(int a, int b){
   return a+b;
}

int Sub(int a, int b){
   return a-b;
}

int Mul(int a, int b){
   return a*b;
}

 

func.cpp에서의 iStatic과 main.cpp에서의 iStatic은 같은 녀석인가?

같은 녀석이 아니다!!!!!

#include의 뜻은 복붙이다. (가져와서 붙여 넣는 것) 

그런데 static는 선언 위치가 파일이 되버리니까 main파일 iStatic 따로 func 파일 iStatic 따로 각자 그 지역 전용으로 사용된다 (구별된다!!! - 컴파일러가 나중에 구별할 수 있다)

 

그럼 진짜 양쪽 파일 포함 전국구에서 먹히는 그런 전역변수는 어떻게 만들까???

외부변수(extern)를 사용하면 된다!

- extern을 헤더에 배치할 때는 초기화를 하면 안된다!

common.h

static int g_iStatic =0; 
extern int g_iExtern;       //초기화하면 안됨

- 이것은 변수를 선언한 것이 아니라 g_iExtern이라는 변수가 있다라고만 알려주는 역할이다
(확정지은거 X, 있을거다~라고 알려준거)

- 그럼 참조한 파일에서 g_iExtern이라는 변수가 있다는 것을 알게됨

 

그럼 진짜 있게 하려면 어떡해야돼?

어떤 파일있던 상관이 없다.

어떤 파일에서든 선언해주면 돼.

 

Test.cpp
- 이게 main에 선언되 있어도 되고, func에 선언되 있어도 된다. 아무곳에서나 선언 가능

- 나중에 LINK되어 모든 코드들이 합쳐질 때 연결해줌 ( 즉 어디서 한번만 딱 선언되어 있기만 하면 됨)

int g_iExtern = 0;         //선언

main.cpp

#include <stdio.h>
#include "func.h"
#include "common.h"       //common 참조(복붙)



int main() {

   g_iExtern = 500;     //g_iExtern(외부변수) 사용, 초기화
   
   return 0;
}

func.cpp

#include "func.h"
#include "common.h"
#include <stdio.h>

int Add(int a, int b){

   printf("g_iExtern의 값은: %d", g_iExtern);     //g_iExtern 사용
   
   return a+b;
}

int Sub(int a, int b){
   return a-b;
}

int Mul(int a, int b){
   return a*b;
}

iExtern 변수를 main 또는 func에서 선언해도 됨, 나중에 다~~~~ 합쳐지니까


참고영상 

https://www.youtube.com/watch?v=R9RmoQzpxxw&list=PL4SIC1d_ab-aOxWPucn31NHkQvNPHK1D1&index=23 

 

 

- F12를 누르면 선언된 곳으로 갈 수 있다.

- 메모리랑 연결하면서 생각해야 한다.

 

'C++' 카테고리의 다른 글

[C++] main(int argc, char *arvg[])  (0) 2023.03.07
[C++] ios_base::sync_with_stdio(0)  (0) 2023.03.07
[C++] 배열, 구조체  (0) 2023.02.23
[C++] 재귀함수  (0) 2023.02.23
[C++] 팩토리얼 함수 구현하기  (0) 2023.02.23