오늘은 정적변수, 정적 함수에 대한 수업을 들었다.
1. C 메모리 구조
1. 코드(Code) 영역
- 실행할 프로그램의 코드가 저장되는 영역.
- 읽기 전용(Read-Only)으로 설정되어 프로그램 코드가 변경되지 않도록 보호.
- 정적 크기를 가지며 프로그램 실행 중에 크기가 변하지 않음.
2. 데이터(Data) 영역
- 전역 변수와 정적 변수가 저장되는 영역.
- 초기화된 변수는 초기화 영역에, 초기화되지 않은 변수는 BSS(Zero-initialized Segment)에 저장.
- 프로그램 시작 시 고정된 크기(일반적으로 약 1MB)로 메모리를 할당받음.
이 고정된 메모리 내에서 변수를 할당하거나 반환하면서 사용.
3. 스택(Stack) 영역
- 지역 변수와 함수 호출 시 생성되는 스택 프레임이 저장되는 영역.
- 컴파일 타임에 크기가 결정됨.
- LIFO(Last In, First Out) 구조로, 함수 호출 시 메모리가 추가되며 함수가 종료되면 자동으로 메모리 해제.
- 메모리 관리가 자동으로 이루어지므로 상대적으로 안전한 영역.
4. 힙(Heap) 영역
- 동적 메모리 할당(예: malloc, new)이 이루어지는 영역.
- 런타임에 크기가 결정되며, 사용자가 명시적으로 할당과 해제를 관리해야 함.
- 메모리 관리 실수로 인해 메모리 누수가 발생할 수 있음.
- 메모리를 할당받고 반환하지 않으면 점점 누적되는 상황이 발생하게 되면 프로그램 성능 저하나 종료를 초래할 수 있음.
2. 정적 변수
2.1 정적 변수란?
정적 변수는 프로그램이 종료될 때까지 메모리가 유지되는 변수이다.
- 특징:
- 함수를 벗어나도 변수가 소멸되지 않고 유지
- 초기화는 한 번만 진행
- 초기화되지 않은 경우 기본값 0으로 자동 초기화
- 반드시 상수로 초기화
- 함수 매개변수로 사용할 수 없다
- 생명 주기: 프로그램 시작 시 생성 및 초기화 → 프로그램 종료 시 소멸
- 전역 변수와의 차이점: 전역 변수와 유사하지만, 정적 변수는 초기화가 한 번만 이루어지고 이후 값을 유지한
2.2 정적 지역 변수 vs 정적 전역 변수
- 정적 지역 변수
- 선언된 중괄호 {} 내부에서만 사용 가능.
- 한 번 초기화되면 함수 호출 시 초기화를 무시. - 정적 전역 변수
- 선언된 소스 파일 내부에서만 사용 가능.
- 외부 파일에서 접근 불가.
- 전역 변수에 static을 붙이면 범위를 파일 단위로 제한.
2.3 정적 변수 선언
static int nData{};
- static을 붙여 정적 변수를 선언.
정적 변수와 일반 변수의 차이는 함수 호출을 통해 확인 가능하다.
#include <iostream>
void func();
int main()
{
func();
func();
func();
}
void func()
{
static int nData1{}
int nData{};
nData1++;
nData++;
printf("정적 변수 : %d\n", nData1);
printf("지역 변수 : %d\n", nData);
}
출력 결과는
- nData (지역 변수): 1, 1, 1 / nData1 (정적 변수): 1, 2, 3
즉 지역 변수는 함수 호출 시마다 새로 메모리가 할당되고 초기화되지만, 정적 변수의 경우 프로그램 시작 시 메모리가 할당되어 값을 유지하게 되어 저런 결괏값이 나오게 되는 것이다.
2.4 클래스 내 정적 변수
#include <iostream>
class C_DATA
{
private:
static int m_nStatic;
int m_nData;
public:
C_DATA() = default;
void setData(int nData);
void print();
};
int main()
{
C_DATA c1{};
C_DATA c2{};
c1.setDataStatic(100);
c1.print();
c2.setData(10);
c2.print();
}
void C_DATA::setData(int nData)
{
m_nStatic = nData;
m_nData = nData;
}
void C_DATA::print()
{
printf("static %d\n", m_nStatic);
printf("member %d\n", m_nData);
}
- class는 설계도로 메모리는 실제 객체 생성 시 할당된다.
- static 변수는 클래스 선언 시 초기화되지 않아 링크 오류가 발생하게 된다.
즉, class 안에 정적 변수를 선언하게 되면 class의 손을 들어준 것이다.
그렇다면 해결방법은 무엇일까?
클래스 외부에서 정적 변수 초기화를 해주면 된다.
자료형 소속::이름 {};
int C_DATA::m_nStatic{};
- 정적 변수는 클래스 전체에서 공유되며, 객체가 여러 개 생성돼도 하나의 메모리만 사용.
C_DATA::C_DATA() :
m_nData{},
// m_nStatic{}
{
}
생성자를 호출하여 초기화를 하는 경우 static을 초기화하게 되면 오류가 발생하게 된다.
- C_DATA는 선언하면서 메모리가 할당
- 정적 변수는 프로그램 시작 시 메모리가 할당
즉, 메모리가 할당되는 시기가 다르기에 객체 생성 시 초기화하려 하면 충돌이 일어나 초기화가 안 되는 것이다.
#include <iostream>
class C_DATA
{
private:
static int m_nStatic;
int m_nData;
public:
C_DATA();
void setData(int nData);
void print();
static void setDataStatic(int nData);
};
int C_DATA::m_nStatic{};
int main()
{
C_DATA c1{};
C_DATA c2{};
C_DATA::setDataStatic(100);
c1.print();
c2.setData(10);
c2.print();
}
C_DATA::C_DATA() :
m_nData{}
{
}
void C_DATA::setData(int nData)
{
m_nStatic = nData;
m_nData = nData;
}
void C_DATA::print()
{
printf("static %d\n", m_nStatic);
printf("member %d\n", m_nData);
}
void C_DATA::setDataStatic(int nData)
{
m_nStatic = nData;
}
2.5 정적 변수 활용
// data.h
#pragma once
class C_DATA
{
private:
static int m_nData;
private:
C_DATA() = default;
public:
static void setData(int nData);
static int getData();
};
// data.cpp
#include "data.h"
int C_DATA::m_nData{};
void C_DATA::setData(int nData)
{
m_nData = nData;
}
int C_DATA::getData()
{
return m_nData;
}
// main.cpp
#include <iostream>
#include "data.h"
int main()
{
C_DATA::setData(100); // 전역변수 코딩
printf("%d\n", C_DATA::getData());
}
- 정적 변수는 초기화 메모리 할당이 중요하다.
- data.cpp에서 int C_DATA::m_nData {}를 선언하지 않으면 정적 변수가 초기화되지 않아 에러 발생
- 정적 인터페이스와 지역 인터페이스를 구분하여 명확히 관리할 것
- C_DATA 생성자를 pritvate으로 설정해 정적 클래스 역할 수행, 그렇기에 네임스페이스를 이용하여 선언
[ C_DATA::setData(100); ]
'C++' 카테고리의 다른 글
[강의] 12월 18일 수업정리 (1) | 2024.12.18 |
---|---|
[강의] 12월 17일 수업정리 (0) | 2024.12.17 |
[강의] 12월 13일 수업정리 (0) | 2024.12.13 |
[강의] 12월 12일 수업정리 (0) | 2024.12.13 |
[강의] 12월 11일 수업정리 (0) | 2024.12.11 |