CS 공부

[C#] 변수 종류와 키워드

때류기 2024. 8. 9. 21:37

C#은 객체 지향 프로그래밍 언어로, 다양한 종류의 변수를 지원합니다. 변수는 데이터의 값을 저장하기 위해 사용되며, 변수의 범위와 수명에 따라 전역 변수, 지역 변수, 정적 변수, 매개 변수 등으로 나뉩니다. 또한 readonly와 const 키워드는 변수의 불변성을 보장하기 위해 사용됩니다. 이번 글에서는 각 변수의 특성과 사용법에 대해 자세히 설명하고, 관련 예제 코드를 함께 보여드리겠습니다.

 

 


1. 전역 변수(Global Variable)

전역 변수는 클래스 내부, 메서드 외부에 선언되어 클래스의 모든 메서드에서 접근할 수 있는 변수입니다. 그러나 이 변수는 클래스의 인스턴스와 밀접하게 연관되어 있으며, 클래스의 인스턴스가 생성될 때 힙(Heap) 메모리에 할당되고, 인스턴스가 소멸될 때 함께 해제됩니다. 따라서, 전역 변수는 인스턴스에 종속되며, 클래스의 생명 주기와 함께 합니다.

 

 

특징:

  • 클래스 내의 모든 메서드에서 접근 가능
  • 클래스가 로드된 이후부터 메모리에 상주
  • 메모리 사용량이 많아질 수 있음

 

 

저장 영역:

  • 힙(Heap): 전역 변수는 클래스의 인스턴스 멤버로 선언될 경우 힙 메모리에 할당됩니다.

 

 

생명 주기:

  • 생성 시점: 클래스의 인스턴스가 생성될 때 힙 메모리에 할당됩니다.
  • 소멸 시점: 클래스 인스턴스가 더 이상 사용되지 않을 때, 가비지 컬렉터(Garbage Collector)에 의해 메모리에서 해제 됩니다.

 

 

예제:

public class GlobalVariableExample
{
    // 전역 변수 선언
    private int globalCounter = 0;

    public void IncrementCounter()
    {
        globalCounter++;
        Console.WriteLine("Counter: " + globalCounter);
    }

    public void ResetCounter()
    {
        globalCounter = 0;
        Console.WriteLine("Counter reset to " + globalCounter);
    }
}

 

 

 


2. 지역 변수(Local Variable)

지역 변수는 특정 블록(메서드, 루프, 조건문 등) 내에서 선언되어 그 블록 내에서만 사용 가능한 변수입니다. 지역 변수는 스택(Stack)에 할당되며 블록이 종료되면 지역 변수는 메모리에서 해제됩니다.

 

 

특징:

  • 선언된 블록 내에서만 유효
  • 블록이 종료되면 메모리에서 해제

 

 

저장 영역:

  • 스택(Stack): 스택 메모리 영역에 할당됩니다. 스택은 메서드 호출 시 활성화되는 메모리 영역으로, 매우 빠르게 할당 및 해제됩니다.

 

 

생명 주기:

  • 생성 시점: 메서드 또는 블록이 실행될 때 스택에 할당됩니다.
  • 소멸 시점: 메서드 또는 블록이 종료되면 스택에서 자동으로 해제됩니다.

 

 

예제:

public class LocalVariableExample
{
    public void PrintSum()
    {
        // 지역 변수 선언
        int a = 10;
        int b = 20;
        int sum = a + b;

        Console.WriteLine("Sum: " + sum);
    }
}

 

 

 


3. 매개 변수(Parameter)

매개 변수는 메서드 또는 생성자 호출 시 전달되는 값을 받기 위해 사용하는 변수입니다. 메서드 내에서 지역 변수로 취급되어 스택에 할당되며, 메서드 호출이 끝나면 메모리에서 해제됩니다.

 

 

특징:

  • 메서드 또는 생성자 호출 시 값을 전달받기 위해 사용
  • 메서드 내에서 지역 변수로 취급

 

 

할당 영역:

  • 스택(Stack): 매개 변수는 메서드 호출 시 스택에 할당됩니다.

 

 

생명 주기:

  • 생성 시점: 메서드가 호출될 때 스택에 할당됩니다.
  • 소멸 시점: 메서드가 종료되면 스택에서 해제됩니다.

 

 

예제:

public class ParameterExample
{
    public void PrintMessage(string message)
    {
        // message는 매개 변수로서 메서드 호출 시 전달된 값을 가짐
        Console.WriteLine(message);
    }
}

 

 

 


4. 키워드

C#에서 변수와 관련된 다양한 키워드들이 있습니다. 각각의 키워드는 변수의 특성과 사용 방법을 정의하며, 메모리 관리와 생명 주기에도 영향을 미칩니다. 아래에서는 static, readonly, const 키워드에 대해 설명하겠습니다.

 

 

 

1. 정적 변수(Static Variable)

정적 변수는 클래스에 종속되며, 클래스의 모든 인스턴스가 공유하는 변수입니다. 클래스가 로드될때 한 번만 초기화되며, 프로그램이 종료될 때까지 정적 메모리 영역에 할당됩니다.

 

 

특징:

  • 클래스의 모든 인스턴스가 공유
  • 클래스가 로드될 때 한 번만 초기화
  • 클래스의 인스턴스 없이도 접근 가능

 

 

할당 영역:

  • 정적 메모리 영역(Static Memory Area): 정적 변수는 프로그램 실행 시작 시 정적 메모리 영역에 할당됩니다. 이 메모리 영역은 프로그램 전체에서 공유됩니다.

 

 

생명 주기:

  • 생성 시점: 프로그램이 시작될 때 클래스가 로드되면서 정적 메모리 영역에 할당됩니다.
  • 소멸 시점: 프로그램이 종료될 때까지 메모리에 유지됩니다.

 

 

예제:

public class StaticVariableExample
{
    // 정적 변수 선언
    public static int staticCounter = 0;

    public void IncrementStaticCounter()
    {
        staticCounter++;
        Console.WriteLine("Static Counter: " + staticCounter);
    }
}

 

 

 

2. readonly 변수

readonly 키워드는 런타임에 한 번 초기화된 후 더 이상 변경할 수 없는 변수를 정의할 때 사용됩니다. 생성자에서 초기화할 수 있으며, 런타임 동안 불변성을 유지합니다.

 

 

특징:

  • 런타임에 값을 설정할 수 있지만, 이후 변경할 수 없음
  • 생성자에서 초기화 가능
  • 인스턴스 멤버로 선언될 경우 힙 메모리에, 정적으로 선언될 경우 정적 메모리 영역에 할당

 

 

할당 영역:

  • 힙(Heap): readonly변수가 클래스의 인스턴스 멤버로 선언되었다면 힙 메모리에 할당됩니다.
  • 정적 메모리 영역(Static Memory Area): readonly 변수가 정적으로 선언되었다면, 정적 메모리 영역에 할당됩니다.

 

 

생명 주기:

  • 생성시점: 인스턴스 멤버인 경우, 클래스 인스턴스가 생성될 때 힙 메모리에 할당됩니다. 정적 멤버인 경우, 클래스가 로드될 때 정적 메모리 영역에 할당됩니다.
  • 소멸 시점: 인스턴스 멤버인 경우, 클래스 인스턴스가 소멸될 때 해제됩니다. 정적 멤버인 경우, 프로그램이 종료될 때 해제 제됩니다.

 

 

예제:

public class ReadOnlyExample
{
    public readonly int readonlyValue;

    public ReadOnlyExample(int value)
    {
        readonlyValue = value; // 생성자에서 초기화
    }

    public void PrintValue()
    {
        Console.WriteLine("Readonly Value: " + readonlyValue);
    }
}

 

 

 

3. const 변수

const 키워드는 컴파일 타임에 값을 설정하고, 이후 절대 변경할 수 없는 상수를 정의할 때 사용됩니다. const 변수는 컴파일 시점에 이미 상수로 처리되며, 프로그램의 실행 중에 메모리에서 상수로 존재합니다.

 

 

특징:

  • 컴파일 타임에 값을 설정해야함
  • 변경 불가
  • 상수 풀(Constant Pool)이나 IL코드에 포함
  • 기본적으로 static으로 취급되며, 클래스의 인스턴스 없이 접근 가능

 

 

할당 영역:

  • 상수 풀(Constant Pool) 또는 IL코드: const 변수는 컴파일 타임에 상수로 변환되며, 프로그램 실행 중에는 메모리의 상수 풀이나 IL코드에 포함되어 상수로서 존재합니다.

 

 

생명 주기:

  • 생성 시점: 컴파일 타임에 결정되며, 프로그램 실행 중 메모리에 상수로 존재합니다.
  • 소멸 시점: 프로그램이 종료될 때 까지 상수로 유지됩니다.

 

 

예제:

public class ConstExample
{
    public const int constantValue = 100;

    public void PrintConstant()
    {
        Console.WriteLine("Constant Value: " + constantValue);
    }
}

 

 

 

4. const와 readonly의 차이점

const와 readonly는 C#에서 모두 불변(immutable)값을 정의하는 데 사용되지만, 이 둘에 차이점이 존재합니다. 이 차이점은 성능, 사용 사례, 그리고 메모리 할당 방식에서 서로 다른 결과를 가집니다. 아래에서 const와 readonly의 차이점과 성능 비교를 살펴보겠습니다.

 

 

 

초기화 시점:

  • const: const변수는 컴파일 타임에 값을 할당해야 합니다. 이는 const가 컴파일 시점에 상수로 확정되어야 하며, 이후 변경할 수 없다는 것을 의미합니다.
  • readonly: readonly변수는 런타임에 초기화될 수 있습니다. 보통 생성자에서 초기화되며, 이후 값을 변경할 수 없습니다. 이 때문에 readonly는 생성자에서 초기화할 수 있는 인스턴스 별 값이나 복잡한 객체 등을 사용할 수 있습니다.

 

 

적용 대상:

  • const: const는 숫자, 문자열, 열거형 값과 같이 기본 데이터 형식의 값에만 사용할 수 있습니다. 참조 형식의 경우 string은 예외적으로 사용할 수 있습니다.
  • readonly: readonly는 모든 데이터 형식에 사용할 수 있습니다. 이는 참조 형식뿐만 아니라, 구조체와 같은 값 형식에도 적용할 수 있습니다.

 

 

메모리 할당:

  • const: const값은 컴파일 타임에 확정되어 상수 풀 또는 IL코드에 포함됩니다. 따라서 const변수는 프로그램의 여러 부분에서 재사용될 때, 각기 복사된 값이 코드에 포함됩니다.
  • readonly: readonly변수는 인스턴스 멤버인 경우 힙에, 정적 멤버인 경우 정적 메모리 영역에 할당됩니다. 각 인스턴스 또는 정적 필드로서 독릭접으로 존재합니다.

 

 

유연성:

  • const: const는 값이 확정적이며, 변경할 수 없습니다. 코드에서 const변수의 값이 사용되는 모든 위치에 해당 값이 직접 삽입되므로, 유연성이 떨어질 수 있습니다.
  • readonly: readonly는 런타임에서 값을 설정할 수 있어, 유언성이 더 큽니다. 주로 인스턴스나 정적 생성자에서 설정되며, 런타임에 특정 조건에 따라 값을 설정할 수 있습니다.

 

 

성능 비교

1. 컴파일 시 최적화

  • const: const 값은 컴파일 시점에 값이 결정되며, 사용될 때마다 상수 값 자체가 삽입됩니다. 이는 런타임에서 추가적인 메모리 참조 없이 값을 직접 사용할 수 있음을 의미합니다. 따라서 const는 성능 면에서 매우 효율적입니다.
  • readonly: readonly 값은 런타임에 할당되며, 클래스 인스턴스나 정적 필드에 접근할 때 메모리 참조가 필요합니다. 런타임에 값을 참조하는 비용이 발생하므로, const에 비해 약간의 성능 저하가 있을 수 있습니다.

 

 

2. 실제 사용 시 성능

  • const: 상수는 코드가 컴파일될 때 값이 인라인되어 삽입되므로, 메모리 접근을 최소화하고 성능을 극대화할 수 있습니다.
  • readonly: 비록 메모리 참조가 필요하지만, 이 성능 차이는 대부분의 실제 사용 사례에서 미미합니다. 그러나 대량의 반복 작업에서 메모리 접근이 잦다면 const가 조금 더 나은 성능을 보일 수 있습니다.

 

 

어느 것을 사용할지 선택하는 기준

  • const를 사용하는 경우:
    • 컴파일 타임에 결정 가능한 고정된 상수 값이 있을 때.
    • 성능이 매우 중요한 부분에서 상수를 자주 참조할 때.
    • 단순한 숫자, 문자열 등의 기본 형식 값을 사용할 때.

 

 

  • readonly를 사용하는 경우:
    • 런타임에 초기화가 필요한 값이 있을 때.
    • 참조 형식 또는 복잡한 구조체 등, 기본 형식 외의 데이터를 불변 값으로 사용할 때.
    • 인스턴스별로 초기화해야 하거나, 정적 필드에서 초기화가 필요한 경우.

 

 

결론

  • 성능 면에서는 const가 readonly보다 약간 더 효율적입니다. 이는 const가 컴파일 시점에 결정되고, 런타임에 메모리 참조가 필요 없기 때문입니다.
  • 그러나 유연성과 기능 측면에서는 readonly가 더 유리합니다. readonly는 복잡한 데이터 구조나 런타임 조건에 따라 값이 달라질 수 있는 경우에 적합합니다.

따라서, 성능이 가장 중요한 상황에서는 const를, 유연성이나 특정 초기화 논리가 필요한 경우에는 readonly를 사용하는 것이 좋습니다.

 

 

 

 

 


지금까지 C# 변수 종류와 키워드에 대해 알아보았습니다.

현재 글의 내용 중 틀린 부분이나, 지적하실 내용이 있으시다면 언제든지 알려주세요! 읽어주셔서 감사합니다.