본문 바로가기
C++/Unmanaged C++ 강좌 노트

[C++]Static(정적) 키워드

by 계양구놈팽이 2023. 3. 3.

Udemy에서 C++ 언 매니지드 프로그래밍을 수강하면서 배운 내용을 정리한 것입니다.

Static 키워드

  • 범위(scope)의 제한을 받는 전역 변수 : 실행 도중 딱 하나만 존재하는 변수, 단 접근이 제한됨.
  • 제한되는 범위는?
    • 파일 속
    • 네임스페이스 속
    • 클래스 속
    • 함수 속
  •  static 혐오론자들이 존재하기는 함 OOP에 어울리지 않는다고 생각하는 분들.
  • C++는 코드를 소스 파일 단위로 컴파일해서 나온 오브젝트 파일들을 링크 단계에서 서로 연결한다. 소스 코드 파일마다 정의된 이름은 외부 링크나 내부 링크를 통해 서로 연결된다. 
  • 외부 링크로 연결되면 다른 소스 파일에서 이름을 사용할 수 있다.
    • 함수나 전역 변수는 기본적으로 외부 링크가 적용된다.
  • 내부 링크(정적 링크)로 연결되면 같은 파일에서만 사용할 수 있다.
    • static 키워드를 붙이면 내부 링크가 적용된다.

 

Static 변수가 하드웨어 메모리 상에서 딱 하나 존재한다는 것을 명심하자

Extern 키워드

  • 다른 파일의 전역변수에 접근을 가능케 해 줌
  • static과 정반대로 외부 링크를 지정할 때 사용.

함수 속 정적 변수

#include <iostream>

void Accumulate(int number)
{
    static int result = 0;
    result += number;
    std::cout << "result = " << result << std::endl;
}


int main()
{
    Accumulate(10); // print out 10
    Accumulate(20); // print out 20

    return 0;
}

보톰 함수에서 변수를 선언하면 스택에 메모리공간을 할당받고, 함수가 종료하면 스택에서 차례대로 변수를 반환한다.

static int result 변수를 짱 박혀 있음.

위의 함수의 작동로직을 설명하면 다음과 같다.

  1. Accumulate(10)이 호출
  2. static int result는 아직 초기화가 안되었다. 0으로 값을 초기화해 준다,
  3. result의 0에 10을 더해준다. (result == 10)
  4. result = 10이라고 출력
  5. Accumulate(20)이 호출
  6. (static int result는 이미 초기화가 되었기에 호출 않음 값은 여전히 10) result 10에 20을 더해준다. (result == 30)
  7. result = 30이라고 출력
  • result 정적 변수는 오로지 함수로 범위(scope)가 제한된다.
  • main문에서는 죽었다 깨어나도 result에 접근이 불가하다.
NOTE static 변수를 따로 만들어서 상태를 관리하지 말고, 상태를 객체 안에서 관리하게 만드는 게 좋다.

class 속 정적 멤버 변수

  • 각 클래스당 하나의 copy만 존재
  • 개체의 메모리 레이아웃의 일부가 아님
  • 클래스 메모리 레이아웃에 포함
  • exe파일 안에 필요한 메모리가 잡혀 있음
    • 컴파일러가 이 변수의 인스턴스가 몇 개 존재해야 하는지 알고 있다. Only ONE

 

어떻게 실전에서 사용할 것인가 

  • 함수 안에서 정적 변수를 넣지 말 것
    • 클래스 안에 넣을 것
  • 전역변수 대신 정적 멤버변수를 쓸 것
    • scope를 제한하기 위해
  • C스타일의 정적 변수를 쓸 이유가 없음 -> OOP로 할 때는 굳이 할 필요가 없기는 한데, 현업에서는 여전히 쓰는 경우 있다.

 

정적 멤버 함수

  • 논리적인 범위에 제한된 전역 함수
  • 해당 클래스의 정적 멤버에만 접근 가능
    • 개체의 멤버변수에는 접근 불가
  • 개체가 없이도 정적 함수를 호출할 수 있음
    • Math::Square(10);

정적 멤버 함수 예시)

sample_math.h

#pragma once
#incldue <cmath>

namespace samples
{
	class Math
	{
	public:
		static int Ceil(float value);
		static int Floor(float value);
		static float Power(float value, float power);
		static int Round(float value);
		static float Square(float value);
		
	/*누군가가 Math의 객체를 만들기를 원하는 클래스가 아니다. 
	생성자를 private에 넣어주면 방지가능*/
	private:
		Math() {};

	};
}

sample_math.cpp

#include "sample_math.h"


namespace samples
{
	// 올림 함수
	int Math::Ceil(float value)
	{
		int intValue = static_cast<int>(value);
		if (value == static_cast<float>(intValue))
		{
			return intValue;
		}
		return intValue + 1;
	}

	//내림 함수
	int Floor(float value)
	{
		return static_cast<int>(value);
	}

	//멱급수 함수
	float Power(float value, float power)
	{
		return pow(value, power);
	}

	//반올림 함수 무조건 내림을 하되 0.5만큼 올리고 소숫점을 제거
	int Round(float value)
	{
		return static_cast<int>(value + 0.5f);
	}

	float Square(float value)
	{
		return value * value;
	}
}

반복 사용에 용이하고, 메모리 공간을 여러 번 할당 받지 않아도 되는 정적 멤버 함수를 가진 Class가 완성되었다.