주녘공부일지

[C#] 값 형식과 참조 형식 ( + 제네릭 형식, 포인터 형식 ) 본문

C#/Definition, Etc

[C#] 값 형식과 참조 형식 ( + 제네릭 형식, 포인터 형식 )

주녘 2023. 9. 29. 16:59
728x90

1. 값 형식

- 인스턴스화 시에 모든 인스턴스를 실제로 할당

- 인스턴스 배정 시 인스턴스가 복사

- 거의 모든 내장 형식, 구조체, 열거형 형식

 ex) 수치(int, float, etc), 논리(bool), 문자(char), etc

// 값 형식 구조체
public struct Point { public int X, Y; }

static void Main()
{
    Point p1 = new Point();
    p1.X = 7;
    
    Point p2 = p1; // 배정에 의해 복사
    
    Console.WriteLine(p1.X); // 7
    Console.WriteLine(p2.X); // 7
    
    p1.X = 9;
    
    Console.WriteLine(p1.X); // 9
    Console.WriteLine(p2.X); // 7
}

2. 참조 형식

- 인스턴스화한 후에 별도로 명시적으로 인스턴스화하기 전엔 null 참조만 할당

- 데이터의 주소(참조)는 스택 영역, 데이터의 값은 힙 영역에 저장

- 인스턴스 배정 시 참조만 복사

- 모든 클래스, 배열, 대리자, 인터페이스 형식

 ex) 클래스(Class), 인터페이스(Interface), 배열(Array), 대리자(Delegate), 객체(Object), 문자열(String), etc

// 참조 형식 클래스
public class Point { public int X, Y; }

static void Main()
{
    Point p1 = new Point();
    p1.X = 7;
    
    Point p2 = p1; // p1의 참조를 복사
    
    Console.WriteLine(p1.X); // 7
    Console.WriteLine(p2.X); // 7
    
    p1.X = 9;

    Console.WriteLine(p1.X); // 9
    Console.WriteLine(p2.X); // 9
}

+ ref 수정자에 의해 참조되는 데이터는 스택 메모리에 있는 데이터일 수 있음

3. 제네릭 형식 <T>

- 서로 다른 형식들에 대해 재사용할 수 있는 코드를 작성하기 위해 사용되는 메커니즘

- 형식 안정성을 높이고 캐스팅과 박싱을 줄이기 위한 수단이 됨 (일반화, 특수화)

public class Stack<T>
{
    int position;
    T[] data = new T[100];
    public void Push (T obj) => data[position++] = obj;
    public T Pop()           => data[--position];
}

public void Main()
{
    var stack = new Stack<int>();
    stack.Push(5);
    stack.Push(10);
    int x = stack.Pop();  // x는 10
    int y = stack.Pop();  // y는 5
}

https://godgjwnsgur7.tistory.com/115

 

[C#] 제네릭 (Generic)

제네릭 (Generic) - 서로 다른 형식들에 대해 재사용할 수 있는 코드를 작성하기 위해 사용하는 메커니즘 - 형식 안정성을 높이고 캐스팅과 박싱을 줄이기 위한 수단이 됨 (일반화, 특수화) + 제네릭

godgjwnsgur7.tistory.com

4. 포인터 형식

- 포인터를 통한 직접적인 메모리 조작을 하기 위해서는 /unsafe 옵션을 지정해서 컴파일한 경우에만 허용되어 사용 가능

- C API와 연동에 필요하지만, 관리되는 힙 바깥의 메모리에 접근하거나 핫스팟을 최적화하는데도 유용

 

주소 연산자 ( & ) 변수의 주소를 담은 포인터를 돌려줌
역참조 ( * ) 포인터의 주소에 있는 변수를 돌려줌
포인터-멤버 ( -> ) 구문 단축용으로 사용됨  // ex) x->y == (*x).y

 

ex) 포인터를 이용해서 비트맵을 처리하는 예시 코드

unsafe void BlueFilter(int[,] bitmap)
{
    int length = bitmap.Length;
    fixed (int* b = bitmap)
    {
        int* p = b;
        for(int i = 0; i < length; i++)
            *p++ &= 0xFF;
    }
}

+ fixed문

가비지 컬렉션에 의해 포인터가 가리키는 객체가 다른 곳으로 이동되지 않게 관리되는 객체를 고정하는 역할

( 단, 실행시점 효율성이 나빠질 수 있으므로, 가능한 잠깐 사용하며 고정된 블록 안에서는 힙 할당을 피하는 것이 좋다. )

 

 

참고도서) C# 6.0 완벽가이드

728x90