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

꿈별·2023년 3월 9일
0

C++

목록 보기
9/27
이번 포스트부터 어소트락 2021 C++강의를 위주로 정리하려고 한다. 
(이전 포스트는 굳이 삭제하지 않고 강의 내용을 포함해서 수정함..)

변수의 종류

(1) 지역 변수
👉 (1) : 스택 영역 사용

(2) 전역 변수

  • (3) 정적 변수 (static)
  • (4) 외부 변수 (extern)

👉 (2), (3), (4) : 데이터 영역 사용


✔ (1) 지역 변수

  • 함수 내부에 정의된 변수로, 함수의 매개변수도 지역변수에 해당한다.

  • 유효 범위
    : 생성된 함수나 블록 내에서만 접근 가능

  • 같은 범위 내에서 동일한 이름의 변수는 중복 선언할 수 없다.

int main()
{
	int a = 1;
    int a = 2; // Error
}

  • 중첩된 블록 내부에 정의된 변수는 중첩된 블록이 끝나면 소멸한다.
    블록 : 중괄호로 둘러싸인 부분
int main()
{
    int month = 3;
    {
        int day = 13;
    }//day 소멸
    return 0;
}//month 소멸

  • 변수명이 같을 때, 블록 기준으로 바깥에서 선언된 전역 변수보다 지역 변수로 선언된 것이 우선순위가 높다.

  • 변수는 함수 내부에서 생성되어 스택 영역에 저장되며, 함수가 종료될 때 소멸한다.

int main()
{
	int a(1);
    float f(1.23);
    
    return 0;
}
// a과 f 모두 main() 함수가 종료될 때,
// 즉 유효 범위를 벗어날 때 소멸한다.

✔ (2) 전역 변수

  • 함수 외부에서 선언되는 변수. But 함수 내에서도 사용 가능
  • 반드시 상수로 초기화해야 하며, 초깃값을 지정하지 않으면 0으로 자동 초기화된다.
  • 프로그램 시작 시 생성 / 프로그램 종료 시 소멸 (지속기간 없음)
    • 데이터 영역에 있기 때문임
      (프로그램 최초 실행 시 데이터 영역에 메모리 할당받음)
  • 유효 범위
    : 프로젝트 파일 전체

전역 변수 종류

  1. 정적 변수 (static)

  2. 외부 변수 (extern)
    : 다른 파일에서도 사용이 가능하며 메모리를 공유함

  • 전역변수는 기본적으로 extern이며 extern 키워드는 생략 가능
    • extern 키워드가 생략된 전역 변수 )
      : 다른 파일에서 사본으로 사용함. 별개의 메모리
    • extern 키워드가 붙은 전역 변수 )
      : 다른 파일에서 메모리 함께 공유. 동일 메모리

-> 모두 데이터 영역을 사용한다.


✔ (3) 정적 변수

static int g_iStatic = 0;
  • static 키워드가 붙은 전역 변수로, 해당 cpp 파일 내에서만 사용 가능
  • 반드시 상수로 초기화해야 하며, 초깃값을 지정하지 않으면 0으로 자동 초기화된다.
  • 프로그램 시작 시 생성되어 프로그램 종료 시 소멸

여기까지는 전역 변수의 특징과 같음


전역 변수 vs 정적 변수 차이점

  • 전역 변수) 프로그램 전체에서 사용 가능
    정적 변수) 해당 블록/함수 안에서만 사용 가능

선언 위치에 따른 차이

"정적" 이란 것은 움직이지 않는 것. 즉 선언된 위치에만 있는 것을 의미한다.

  • 함수 외부에 선언된 정적 변수

    • 해당 cpp 파일에 선언된 것으로, 해당 파일 전용 변수다.
      -> 따라서 파일마다 같은 이름의 정적 변수가 선언되어 있어도 구별할 수 있다.
      -> 전역 변수처럼 네이밍 규칙에 영향을 받지 않는다는 것

  • 함수 내부에 선언된 정적 변수

    • 이 때 정적 변수는 스택 영역이 아닌 데이터 영역을 사용한다.
    • 데이터 영역을 사용하기 때문에 함수의 호출&종료에 관계없이 유지되지만, 선언된 함수 내에서만 사용 가능

예시

void Test()
{
	static int i = 0;
    int a = 0;
}

-> Test() 함수가 호출될 때, a가 포함된 호출 스택이 메모리에 할당된다.
i는 호출 스택에 포함되지 않고, 데이터 영역에 존재한다.

int g_i = 0;

void Test()
{
	static int i = 0;
	int a = 0;
   	i = 100; //함수 안에서는 호출 OK 
}

int main()
{
    Test();
    g_i = 100; //전역 변수라 호출 OK
    i = 50; //Error
    
    return 0;
}

-> ❗ main 함수에서 Test 함수의 정적 변수인 i호출할 수 없다.

  • 함수 안에 선언된 정적 변수의 초기화는 최초 실행 시 한 번만 수행되며, 그 이후엔 초기화 구문을 건너뛴다.
int g_i = 0;
static int i = 0;

int Test()
{
    ++g_i;
    ++i;
    return i;
}

int main()
{
    Test();
    Test();
    Test();
    int iCall = Test();

    g_i = 0;

    //0으로 출력된다.
    cout << "Test 함수 호출 횟수 : " << g_i << endl;

    //4로 출력된다.
    cout << "Test 함수 호출 횟수 : " << i << endl;

    return 0;
}
  • 전역 변수 g_i
    : 다른 함수에서 접근해서 사용할 수 있기 때문에, 예시의 g_i = 0;처럼 값이 변경되는 걸 막을 수 없음

  • 정적 변수 i
    : 함수 내에서만 사용하므로, 함수를 수정하지 않는 한 외부에서 접근해 수정할 방법이 없음

정적 변수 결론

  • 정적 변수는 함수 안에서 선언했을 경우, 해당 함수에서만 접근 가능하다.
  • 데이터 영역을 사용하기 때문에 함수의 호출과 종료에 관계없이 프로그램 실행 내내 유지시킬 수 있다.

❗앞서 말한 분할 구현의 문제점(다른 파일에선 전역 변수를 알지 못하는)을 해결하는 방법으로는 적합하지 않다.

// [common.h]
static int g_iStatic = 0;

-> 이처럼 헤더에 정적 변수를 초기화해 두고, 여러 cpp 파일에서 include하게 된다면.
각 파일의 g_iStatic는 메모리가 공유되는 같은 변수가 아니라, 이름만 같고 파일마다 따로 사용하는 별개의 정적 변수이다.


💡 분할 구현의 문제점 해결

✔ (4) 외부 변수

  • extern 붙은 전역 변수를 외부 변수라고 한다.

  • extern 키워드는 생략 가능. 전역 변수는 디폴트로 extern

    • extern 키워드 생략
      : 다른 파일에서 사본으로 쓰임. 별개의 메모리 사용
    • extern 키워드 사용
      : 다른 파일과 메모리를 공유한다.
      -> 이미 메모리에 할당되어 있는(초기화된) 다른 파일의 전역 변수와 메모리를 공유하겠다고 선언할 때는 extern 키워드 생략 불가
  • 값이 바뀔 위험이 없는 const 전역 변수는 extern 키워드를 붙여서, 계속 복사되어 메모리 낭비할 일이 없도록 하는 것이 좋다.

  • 헤더 파일에선 외부 변수 선언만 O, 초기화 X

  • (보통은) 헤더 파일과 같은 이름의 cpp 파일에서 초기화함

  • 선언 예시

//[example.h]
extern int g_iExtern;

-> g_iExtern 이라는 변수가 존재할 거라고 알려주는 것, 사용하려면 초기화 필요
-> 선언은 한 번만 해야 한다.
-> 초기화는 여러 번 해도 상관 없음

❗ 그래서 그 변수가 어디에 있는데?
👉 어떤 파일이든 상관 없다. 어디서든 초기화할 수 있다.

예시

//[func.h]
int Result(int a);
extern int g_iExtern;

-> 외부 변수 g_iExtern와 함수 Result 선언

//[func.cpp]
#include "func.h"
#include <stdio.h>

int g_iExtern = 10;
int Result(int a)
{
	printf("g_iExtern : %d ", a);
	return a;
}

-> g_iExtern 10으로 초기화
-> 함수 Result 정의

//[test0304.cpp]
#include "func.h"
int main()
{
	g_iExtern = 500;
	Result(g_iExtern);
	return 0;
}

-> 외부 변수를 선언해 둔 func.h를 include한다.
-> g_iExtern에 500으로 다시 초기화

[출력]
g_iExtern : 500


전체 비교 표

지역 변수전역 변수정적 변수외부 변수
선언 위치함수/블록 내부함수 외부함수/블록 내부 헤더 파일
유효 범위함수/블록 내부프로그램 전체함수/블록 내부프로그램 전체
메모리 소멸함수 종료시프로그램 종료시프로그램 종료시프로그램 종료시
메모리스택데이터데이터데이터

static 멤버변수, static const 멤버변수 ..

https://ansohxxn.github.io/cpp/chapter8-10/
static 멤버 변수는 클래스 내에서 선언만 가능, 정의X
(클래스의 모든 객체들이 공동으로 사용하는 것이므로 프로그램이 끝날 때까지 모든 객체가 동일하도록 유지되어야 한다. 그래서 전역 범위에서만 정의할 수 있음)


[참고]
https://youtu.be/pKALaRH3rSc
https://boycoding.tistory.com/169
https://deramgogi123.tistory.com/26
https://ansohxxn.github.io/cpp/chapter4-1/
https://ansohxxn.github.io/cpp/chapter4-2/
http://www.tcpschool.com/c/c_function_variableScope

0개의 댓글