이번 포스트부터 어소트락 2021 C++강의를 위주로 정리하려고 한다.
(이전 포스트는 굳이 삭제하지 않고 강의 내용을 포함해서 수정함..)
(1) 지역 변수
👉 (1) : 스택 영역 사용
(2) 전역 변수
👉 (2), (3), (4) : 데이터 영역 사용
함수 내부에 정의된 변수로, 함수의 매개변수도 지역변수에 해당한다.
유효 범위
: 생성된 함수나 블록 내에서만 접근 가능
같은 범위 내에서 동일한 이름의 변수는 중복 선언할 수 없다.
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() 함수가 종료될 때,
// 즉 유효 범위를 벗어날 때 소멸한다.
정적 변수 (static)
외부 변수 (extern)
: 다른 파일에서도 사용이 가능하며 메모리를 공유함
-> 모두 데이터 영역을 사용한다.
static int g_iStatic = 0;
여기까지는 전역 변수의 특징과 같음
- 전역 변수) 프로그램 전체에서 사용 가능
정적 변수) 해당 블록/함수 안에서만 사용 가능
"정적" 이란 것은 움직이지 않는 것. 즉 선언된 위치에만 있는 것을 의미한다.
함수 외부에 선언된 정적 변수
함수 내부에 선언된 정적 변수
예시
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는 메모리가 공유되는 같은 변수가 아니라, 이름만 같고 파일마다 따로 사용하는 별개의 정적 변수이다.
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
| 지역 변수 | 전역 변수 | 정적 변수 | 외부 변수 | |
|---|---|---|---|---|
| 선언 위치 | 함수/블록 내부 | 함수 외부 | 함수/블록 내부 | 헤더 파일 |
| 유효 범위 | 함수/블록 내부 | 프로그램 전체 | 함수/블록 내부 | 프로그램 전체 |
| 메모리 소멸 | 함수 종료시 | 프로그램 종료시 | 프로그램 종료시 | 프로그램 종료시 |
| 메모리 | 스택 | 데이터 | 데이터 | 데이터 |
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