C++

[강의] 12월 16일 수업정리

k-codestudy 2024. 12. 16. 18:06

오늘은 정적변수, 정적 함수에 대한 수업을 들었다.

 

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 정적 변수란? 

 

정적 변수는 프로그램이 종료될 때까지 메모리가 유지되는 변수이다.

  • 특징:
    1. 함수를 벗어나도 변수가 소멸되지 않고 유지
    2. 초기화는 한 번만 진행
    3. 초기화되지 않은 경우 기본값 0으로 자동 초기화
    4. 반드시 상수로 초기화
    5. 함수 매개변수로 사용할 수 없다
  • 생명 주기: 프로그램 시작 시 생성 및 초기화 → 프로그램 종료 시 소멸
  • 전역 변수와의 차이점: 전역 변수와 유사하지만, 정적 변수는 초기화가 한 번만 이루어지고 이후 값을 유지한

 

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