250x250
Notice
Recent Posts
Recent Comments
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

minjea.dev의 코딩블로그

[c#] ref 그리고 out 본문

코딩강좌/c#

[c#] ref 그리고 out

minjea.dev 2022. 4. 25. 12:00
728x90

이번 강좌는 저번에 만든 구조체인 exStruct의 코드를 그대로 이용할겁니다. 코드는 다음과 동일합니다.

struct exStruct {
    public int i;
    public int n;
    public string str;
    public string str2;
    
    public exStruct(int i,int n,string str,string str2) {
        this.i = i;
        this.n = n;
        this.str = str;
        this.str2 = str2;
    }
    
    public void printAll() {
        Console.WriteLine("i: "+i+", n:"+n+", str:"+str+", str2:"+str2);
    }
}

저번 강좌에서 말씀드린, 값 형식과 참조형식의 차이에 대해 말씀드렸습니다. c#에서는 값 형식을 참조로 전달하는것을, 참조에 의한 호출이라고 하는데, 이를 지원하기 위해 ref와 out이라는 지원합니다.

 

ref

ref 예약어를 사용할때는 이 예약어를 두군데에서 사용해야하는데, 매개변수를 선언할때, 매개변수 타입 앞에 ref 예약어를 붙여야 하고, 메서드를 호출하는 측에서 인자로 넘길때도 ref 예약어를 앞에 붙여야 합니다. 다음은 ref 예약어를 사용한 예제입니다.

exStruct exStruct1 = new exStruct(1,2,"hello","World");
changeVal(ref exStruct1,10,100,"bye, ","World!");
exStruct1.printAll();

static void changeVal(ref exStruct ex, int i, int n, string str, string str2) {
    ex.i = i;
    ex.n = n;
    ex.str = str;
    ex.str2 = str2;
}

그러면 값이 잘 변경된것을 볼수 있습니다. ref 예약어는 사용하게 되면, 메서드의 ex변수가 호출 측의 exStruct1변수와 동일한 주소를 가리키게 됩니다. 따라서, 값을 복사하지 않고, 동일한 메모리 주소를 가리키게 되는 겁니다.

 

ref 키워드가 없이 코드를 작성하면, changeVal의 매개변수인 ex에 전달된 exStruct1의 값이 다른 메모리에 복사되어, 결과적으로는 ex와 exStruct1은 각각 다른 메모리를 가리키게 됩니다. 따라서, ex의 값을 변경해도, 다른 메모리를 가리키고 있으니, exStruct1의 값은 절대로 바뀌지 않습니다. 다만 ref를 사용하면, 스택의 주소가 ex에 전달되기 때문에, ex와 exStruct1은 동일 메모리를 가리키게 되어 결과적으로 ex의 값을 변경한다면, exStruct1의 값도 변경되게 되는 것입니다.

 

또한, 기본 자료형에도 이를 이용할수 있습니다. 다음과 같이 말이죠

int n = 1;
changeVal(ref n,1000);
Console.WriteLine(n);

static void changeVal(ref int n, int i) {
   n = i;
}

 

그러면 n은 1에서 1000으로 값이 변경되게 됩니다. 원하는 값으로 변경된걸 확인할수 있습니다. 그렇지만 명심하세요 ref 예약어를 사용하지 않는다면 값은 변경되지 않는답니다!

 

out

out은 메서드 내에서 생성된 값을 반환하는 예약어로, out으로 넘길 변수는 초기화되지 않아도 되고, out으로 지정된 읹를 받는 메서드는 무조건 해당 변수에 값을 넣어서 반환해야만 합니다. 

 

메서드의 반환값 말고도, 다른 정보를 추가로 전달하고 싶을때 out 예약어를 사용하면 됩니다. 예를 들어, 메서드에서 무언가를 처리할때, 실패했는지, 성공했는지를 알려주고 싶을때처럼 말이죠. 예를 들어 나누기처럼요.

static int divide(int n1, int n2) {
   return n1/n2;
}

여기서 0으로 나누면 에러가 발생하는데, 이를 미연에 방지하기 위해서 코드를 다음과 같이 변경할수도 있는데.

static int divide(int n1, int n2) {
    if (n2 <= 0) return 0;
    return n1/n2;
}

그런데, 정상적인 계산에서도 0이 나올수도 있습니다. 그러면, 0이 나오는 경우를 모두 정상적이지 않은 계산이라고 간주해서만은 안된다는 것입니다. 이럴때 out 키워드를 사용하면 됩니다.

 

그러면 코드를 다음처럼 수정하고 한번 테스트해봅시다.

bool res;
int n = divide(100,10,out res);
if (res) {
    Console.WriteLine(n);
}

static int divide(int n1, int n2, out bool res) {
    if (n2 <= 0) {
        res = false;
        return 0;
    }
    res = true;
    return n1/n2;
}

결과가 10으로 잘 나오는 것을 볼수 있습니다. 작동을 잘 하는것 같죠?

 

오늘 포스트도 여기서 마치도록 하겠습니다. 그럼 내일 새로운 포스트로 인사드리겠습니다~ㅎㅎ

728x90

'코딩강좌 > c#' 카테고리의 다른 글

[c#] 구조체란?  (0) 2022.04.24
[c#] 이벤트 (글이 완성되지 않았으니 보셔서 조회수 늘리지 마세요)  (0) 2022.04.23
[c#] 인터페이스  (0) 2022.04.22
[c#] 델리게이트  (0) 2022.04.21
[c#] 추상 클래스  (0) 2022.04.20