본문 바로가기
기본기 다지기/문법

static 이란?

by -MAYDAY- 2022. 3. 13.

static 이란?

 'static'은 C/C++, Java, Dart 등 여러 프로그래밍 언어에서 사용되는 공통 문법 요소 중 하나로써 적절하게 필요할 때 사용하면 유용하게 쓸 수 있는 문법이다. 여러 언어에서 쓰이는만큼 'static'의 의미를 정확하게 이해하고 사용해보자.

 

- static

 Global 영역에 싱글톤(Singleton)으로 저장되는 특성, 즉 프로그램이 시작하고 끝날 때까지 메모리에 적재되어 해당 데이터가 유지되는 특성을 가진다.

 

 우리가 일반적으로 이야기하는 일반 변수 혹은 일반 함수의 경우 Heap 메모리 영역에 저장되어 Java는 Garbage Collector에 의해 관리되고, C/C++은 프로그래머에 의해 관리된다. 이러한 차이점으로 C/C++은 메모리 관리 측면에서 프로그래머가 수동으로 메모리를 할당하고 해제하는 등의 작업이 필요하고, Java는 Garbage Collector에 의해 알아서 메모리를 할당하고 해제하는 등의 관리가 이루어져 C/C++에 비해 그만큼 비용이 줄어든다.

 

 그러나 'static'으로 선언된 변수나 함수의 경우 heap 영역이 아닌 static 영역에 데이터가 저장되기에 프로그램이 시작하고나서 끝날 때까지 데이터가 유지되는 특성을 가지고 있다. 이러한 특징으로 'static'을 적절하게 사용하지 못하면 메모리 낭비로 인해 프로그램 성능이 저하될 수 있는 특성을 가지고 있어 사용할 때 무엇보다 주의가 필요하다.

 

- static 변수

 static 변수는 전역에서 선언되는 변수로서 어디에서든지 접근이 가능하여 호출할 수 있는 특성을 가지고 있다. 각 언어별 예시를 통해서 static 변수 특징을 알아보자.

 

 (1) C++

#include <iostream>

using namespace std;

static int a = 1; // static 변수
int b = 2; // 일반 변수


void func() {
	static int c = 3; // 함수 내 static 변수
	int d = 4; // 함수 내 일반 변수

	cout << "Normal Method!" << '\n';
	cout << "a = " << a << '\n';
	cout << "b = " << b << '\n';
	cout << "c = " << c << '\n';
	cout << "d = " << d << '\n';
}


void main() {

	func();
}

 C++은 일단 컴파일 에러가 발생하는 부분이 없다. 이 말은 즉, 클래스 바깥에서 static 선언이 가능하고 이를 어떠한 함수 내에서 사용이 가능하다는 것이다. C의 특성을 가지고 있는 C++은 Java와는 다르게 static 선언을 허용하는 범위가 넓다고 볼 수 있다. 

 

출력 결과는 일반, static 변수 모두 정상적으로 출력한다.

 

 이쯤에서 궁금한게 다른 함수에서 특정 함수 내에 선언되어 있는 static 변수를 호출 가능한지 확인해보고 싶었다.

아무리 static으로 선언된 변수라도 다른 함수에 있으면 접근이 불가한 것을 컴파일 오류를 통해 확인했다.

 

 이번엔 클래스를 만들어 클래스 안의 멤버 변수에 static을 사용해보자.

#include <iostream>

using namespace std;

class Number {

public:
	static int num1; // 클래스 안의 static 변수
	int num2;

	Number(int num2) {
		// num1 = 11; 생성자 안에서 초기화 불가
		this->num2 = num2;
	}

};

int Number::num1 = 11; // static 멤버 변수는 클래스 바깥 전역에서 초기화 가능

// 일반 함수
void func() {
	Number num = Number(22);

	cout << "Class num1 = " << Number::num1 << '\n';
	cout << "Instance num1 = " << num.num1 << '\n';
	cout << "Instance num2 = " << num.num2 << '\n';
}


int main(void) {

	func();
	
	return 0;
}

 클래스 안의 멤버 변수를 static을 넣은 것과 안넣은 것으로 구성하고, 일반 멤버 변수는 생성자 안에서 초기화가 가능하지만 static 멤버 변수는 클래스 바깥 전역에서만 초기화가 가능하다.

 

객체를 생성할 때나 클래스를 통해 직접 접근할 때나 동일한 값을 출력한다.

 후에 언급할 Java에서도 같은 특징인 클래스를 통한 static 멤버 변수에 직접 접근하거나 객체 생성을 통해 접근하는 것이 가능하다. 하지만 static 멤버 변수를 접근하기 위해 객체 생성하는 것은 메모리 낭비이니 주의하자!

 

 (2) Java

클래스 바깥에서 선언하면 컴파일 에러가 발생한다.

 일단 Java에서는 클래스 바깥에서 static 관련 선언이 불가하다. (static 함수도 포함)

 

 클래스 내에만 static 사용이 가능한데, static은 멤버 변수 한해서만 사용이 가능하다. 이러한 특징으로 인해 C++과는 차이가 있다고 볼 수 있다.

 

public class BaseCoding {

    static int a = 1;
    int b = 2;

    static void func() {
        int c = 3;

        System.out.println("static Method!");
        System.out.println("a = " + a); // static 멤버 변수 접근 가능
        System.out.println("c = " + c); // static 함수라도 함수 내에서 선언한 일반 변수 접근 가능
    }


    public static void main(String[] args) {
        func();
    }
}

따라서, 위의 코드 같이 수정해야 정상적인 빌드가 가능하다.

 

static 멤버 변수와 함수 내의 일반 변수의 결과가 출력된다.

 

- static 함수

 마찬가지로 static 함수는 전역에서 정의되는 함수로서 어디에서든지 접근이 가능하여 호출할 수 있는 특성을 가지고 있다. 각 언어별 예시를 통해서 static 함수 특징을 알아보자.

 

 (1) C++

#include <iostream>

using namespace std;

static int a = 1; // static 변수
int b = 2; // 일반 변수

// 일반 함수
void func() {
	static int c = 3; // 일반 함수 내의 static 변수
	int d = 4; // 일반 함수 내의 일반 변수

	cout << "Normal Method!" << '\n';
	cout << "a = " << a << '\n';
	cout << "b = " << b << '\n';
	cout << "c = " << c << '\n';
	cout << "d = " << d << '\n';
}

// static 함수
static void func2() {
	static int c = 3; // static 함수 내의 static 변수
	int d = 4; // static 함수 내의 일반 변수

	cout << "static Method!" << '\n';
	cout << "a = " << a << '\n';
	cout << "b = " << b << '\n';
	cout << "c = " << c << '\n';
	cout << "d = " << d << '\n';
}

int main(void) {

	func();
	func2();
	
	return 0;
}

 다행히 static 함수는 일반 함수와 기능적인 측면에서 큰 차이가 없다. 저장되는 메모리 영역이 다를 뿐 소스 코드 상에서는 동일한 기능을 수행한다. 그래서 출력 결과도 동일한 것을 확인할 수 있다.

 

static 함수와 일반 함수 모두 동일한 출력 결과가 나온 것을 확인할 수 있다.

 

 이번엔 클래스를 생성하여 static 함수의 특징을 알아본다.

static 함수 내에서는 일반 멤버 함수에 접근이 불가하다.

 static 함수에는 일반 멤버 함수를 호출할 수 없다. 오직 함수 내의 변수나 static 멤버 변수 호출만 가능하다.

#include <iostream>

using namespace std;

class Number {

public:
	static int num1; // 클래스 안의 static 변수
	int num2;

	Number(int num2) {
		// num1 = 11; 생성자 안에서 초기화 불가
		this->num2 = num2;
	}

	// static 멤버 함수
	static void func() {
		static int num3 = 33;
		int num4 = 44;

		cout << "static Member Method in Class!" << '\n';
		cout << "num1 = " << num1 << '\n';
		cout << "num3 = " << num3 << '\n';
		cout << "num4 = " << num4 << '\n';
	}

	// 일반 멤버 함수
	void func2() {
		static int num3 = 33;
		int num4 = 44;

		func(); // 일반 멤버 함수 내에서 static 멤버 함수 호출 가능

		cout << "Member Method in Class!" << '\n';
		cout << "num1 = " << num1 << '\n';
		cout << "num2 = " << num2 << '\n';
		cout << "num3 = " << num3 << '\n';
		cout << "num4 = " << num4 << '\n';
	}

};

int Number::num1 = 11; // static 멤버 변수는 클래스 바깥 전역에서 초기화 가능


int main(void) {

	Number number = Number(22);

	Number::func(); // 클래스 통한 static 멤버 함수 호출
	number.func(); // 객체 통한 static 멤버 함수 호출
	number.func2(); // 객체 통한 일반 멤버 함수 호출
	
	return 0;
}

 그래서 위와 같은 코드로 작성되어야 컴파일 오류가 생기지 않는다. 추가로 당연한 이야기지만 일반 멤버 함수 내에서 static 멤버 함수 호출이 가능하다.

 

fun2() 함수 내에서 호출된 func() 함수가 출력되는 것을 확인할 수 있다.

 그래서 출력결과를 살펴보면 func2() 함수를 호출할 때 fun() 함수가 호출되고 나서 나머지 func2() 함수의 기능이 수행되는 것을 확인할 수 있다. static 함수도 마찬가지로 static 멤버 함수 호출을 위한 객체 생성은 메모리 관리 측면에서 비효율적이기에 주의해야 한다.

 

 (2) Java

static 함수 내에선 오직 static 변수나 함수만 호출할 수 있다.

 C++과 동일하게 static 함수 내에서는 일반 멤버 변수 혹은 일반 멤버 함수 호출이 불가하다. 그래서 기억하기 static 함수 안에서는 static 멤버 변수 혹은 함수만 호출이 가능하다는 생각을 하면 될 것 같다.

 

public class BaseCoding {

    static int a = 1;
    int b = 2;

    static void func() {
        int c = 3;

        System.out.println("static Method!");
        System.out.println("a = " + a); // static 멤버 변수 접근 가능
        System.out.println("c = " + c); // static 함수라도 함수 내에서 선언한 일반 변수 접근 가능
    }

    void func2() {
        int c = 3;

        System.out.println("static Method!");
        System.out.println("a = " + a); // static 멤버 변수 접근 가능
        System.out.println("b = " + b); // static 멤버 변수 접근 가능
        System.out.println("c = " + c); // static 함수라도 함수 내에서 선언한 일반 변수 접근 가능
    }

    public static void main(String[] args) {
        func();
    }
}

 위와 같이 static인 main함수는 오직 static 함수만 호출이 가능하다. 이렇게 코드를 작성해야 컴파일 에러가 생기지 않는다.

 

static 멤버 함수가 호출되어 그에 대한 결과를 출력한다.

 Java의 전형적인 특징인 OOP로 인해 static은 멤버 함수에 한해서만 사용이 가능하다. 그렇기에 static으로 정의된 main함수 내에서 static 멤버 함수가 호출되어 위와 같이 결과가 출력된다.

 

 

 이렇게 'static'에 대해서 자세히 알아보았다. Java와 C++에 관심이 있는 입장으로서 두 언어의 static 쓰임에 차이가 있는 것을 느꼈고 이번 기회에 자세히 알 수 있게 되었다. 신기한 것은 C++에서는 클래스 안이나 바깥 모두 static 선언을 할 수 있다는 점인데, 아무래도 C의 특성을 가지고 있기에 클래스 안이나 바깥 모두 static 선언이 가능한 듯 싶다. OOP 특성만 가진 Java에서는 불가하다는 점을 보았을 때 OOP를 공부하는 사람 입장에서는 C++보다는 Java가 헷갈리지 않는 측면에서 학습하기 좋은 언어라고 생각한다. C/C++은 속도 측면에서 Java에 비해 굉장히 우월한 위치이지만 그만큼 쓰기에 까다로운(?) 언어라고 생각한다. 하지만 C/C++이 현존하는 언어 중에 가장 낮은 레벨이므로 훌륭한 프로그래머가 되기 위해선 어느 정도 학습할 가치가 있는 언어라는 생각이 든다. 이번 계기를 통해서 새삼 C++과 Java 언어의 차이가 크다는 것을 다시한번 느끼게 되었다.

 

 

- 참고

https://m.blog.naver.com/dd1587/221106199316

 

C언어 static변수(정적변수)

C언어 static변수(정적변수)C언어 static변수에 대해 알아보려고하는데요. static변수는 한글로는 정적변...

blog.naver.com

https://ansohxxn.github.io/cpp/chapter8-10/

 

C++ Chapter 8.10 : static 정적 멤버 변수

인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀 🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!

ansohxxn.github.io

https://wikidocs.net/228

 

07-03 정적(static) 변수와 메소드

이번에는 스태틱(static)에 대해서 알아보자. [TOC] ## static 변수 예를 들어 다음과 같은 HouseLee 클래스가 있다고 하자. *Sample. ...

wikidocs.net

 

'기본기 다지기 > 문법' 카테고리의 다른 글

enum & struct  (0) 2022.06.12
Thread 실습 - Java  (0) 2022.04.16
Thread란?  (0) 2022.04.03
추상클래스(abstract class)와 인터페이스(interface)  (0) 2022.03.27