2011년 12월 4일 일요일

[CODE] C++에서 *와 &의 차이

레퍼런스 변수는 c에서는 작동하지 않는다.


/Users/hajunho$ !gcc
gcc a.c
a.c:8:5: error: expected identifier or '('
int &m = a;
    ^
1 error generated.


 원래 없는데 에러 메시지 타입이야 어떤들 난 모르리. 원소스에(ㅡㅡ; 별거 없어서 안 씀) 몇 줄 추가해 보았다.

#include <stdio.h>

int main()
{
int i[] = {1, 2, 3};
int* j = i;
int a = 10;
int &m = a;
printf("%d", m);

}

C++에서는 먹는데 10이 출력된다. int &m = j 를 대입하면?

g++ a.cpp
a.cpp:7:6: error: non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'int *'
int &m = j;
     ^   ~

1 error generated.

포인터 타입에는 대입될 수 없다고 나온다. j를 *j로 바꾸면 정상 동작한다.

즉, 레퍼런스 변수는 값을 가리키는 변수다.

printf("%d\n", &m);

printf("%d\n", i);

m변수의 주소와 i의 주소를 보면

/Users/hajunho$ !g++
g++ a.cpp
a.cpp:8:16: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
printf("%d\n", &m);
        ~~     ^~
a.cpp:9:16: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
printf("%d\n", i);
        ~~     ^
2 warnings generated.
/Users/hajunho$ ./a.out 
1348565628

1348565628

같다.

결론은 레퍼런스 변수는 NULL 을 가질 수 없고, 값을 지칭하는 변수라는 것.

포인터 변수에 아무것도 쓰지 않으면 주소 연산이 되는 것과 달리 레퍼런스 변수는 값 연산이 되어 버린다. swap 같은 것을 구현하면 코드양이 준다(편리하다고는 하지 않겠다)

즉, 레퍼런스 변수는 따로 메모리를 잡지 않는 변수이다.

[] 연산자 오버로딩에서

int element(int i)
blah, blah
return arr[i];
}
로 되어 있을 때 a.element(10) = 5 로 쓰면 에러다. 이 때 int를 int&로 바꿔주면 가능하다. 값을 리턴하는데 값에다가 값을 대입하니... 레퍼런스는 해당 값이 있는 주소를 반환한다. 레퍼런스 변수에 대입할 때는 값 형태로 대입된다는 사실은 변함없다.

다 알겠지만 포인터 변수 자체의 메모리는 따로 잡힌다. 4바이트, 64비트에서는 8바이트로 고정이다.

동일한 기능을 하는 경우 레퍼런스 변수는 쓰는 것이 더 효율적이라는 말이다.(이론적으로는...)

효율적이란 말은 특정 상황에서 시간이 빠르거나 메모리를 적게 차지하는 경우를 말한다.

그러나 시간의 경우 컴파일 타임도 들어가므로 좀 더 세밀한 측정이 필요한데 별로....

C++은 갈수록 어려워지는게 생산성이 낮아지는 것은 사실이다. 온갖 라이브러리 붙여다가 쓰면 되겠지만

새로운 언어들은 이미 붙어서 나오니까.

왠만하면 객체를 제외하고는 C의 고유 기능으로 쓰는 C++ 프로그래밍을 하는게 좋을 것 같긴하다.

다만 나 같은 경우 이런 생각이 항상 base에 있다. 프로그램을 정말 잘 짜면

혼자서 다 짜면 되고 모듈 나눌 필요도 없이 main에서 쇼부치면 된다. 그러나 어쩔 수 없이 모듈을 나누게 되고 나누어진 모듈 끼리 통신하는게 필요하다. 그게 콜백이던 값 전달이던 메모리 공유던 간에 파라미터를 넘긴다는 것으로 이해할 수 있다. 파라미터를 넘길 때 원 값을 유지하려면 값을 넘겨 복사하면 되고 원 값을 바꾸려면 주소를 넘기면 된다. 그것이 포인터, 또 함수 포인터다. 콜백도 함수포인터로 구현하고 자바에서도 실제적으로 인터페이스로 구현한 껍데기의 주소를 넘기는 방식으로 콜백을 쓴다.

그럼 사실 레퍼런스 변수라는 것은 이상적인 녀석이다. 반복 때문이던 효율성 때문이던 다른 사람이 쓰라기 때문이던 모듈을 나눈다면 주소 교환 방식이 좋다는 것이다. 더 커지면 소켓, 파이프, 디바이스 드라이버, COM, TCP/IP가 들어간 온갖 프로토콜... 이겠지만 원래 변환할 값을 넘기는 것이 맞는 페러다임이다. COPY가 필요하다면 컴파일러에 맡기지 말고, 자료 구조를 하나 만들고 거기서 컨트롤하는게 맞다.

그러나 이런 생각들과 별개로 시장은 너무 빨리 변하고 개발 속도는 느리기에 그냥 이해하고 적당히 맞춰서 쓴다.

안그랬으면 CPU 설계하고 거기 맞는 운영체제 만들고 프레임웍 만들고 했겠지 ^^;;

댓글 없음:

댓글 쓰기

국정원의 댓글 공작을 지탄합니다.

UPBIT is a South Korean company, and people died of suicide cause of coin investment.

 UPBIT is a South Korean company, and people died of suicide cause of coin. The company helps the people who control the market price manipu...