함수내 지역변수 반환문제........
글쓴이: indiebox / 작성시간: 수, 2003/03/05 - 10:40오후
:mrgreen:
c언얼 공부하다 의문점이 있어 질문합니다.
다음코드에서 add()내 i가 선언되고 나서 return될때
제가 알기런 함수가 종료되면서 함수내 지역변수는 stack에서 사라지는 걸로
알고있는데 실행상에는 아무 문제가 없네요.
혹시 add()함수가 종료하고 그값이 sum에 저장되고 난후
사라지는 건가요?
아니면 제가 잘못 알고 있나요?
자세한 답변 부탁 드립니다.
#include <stdio.h>
int add(int a, int b)
{
int i;
i=a+b;
return i;
}
int main()
{
int a=1;
int b=2;
int sum;
sum=add(a, b);
printf("%d\n", sum);
return 0;
}
Forums:
리턴되는 것은 변수 i가 아니라변수 i가 가지고 있는 값입니다.
리턴되는 것은 변수 i가 아니라
변수 i가 가지고 있는 값입니다.
복사본이 전달되는 것이죠.
일난 return i ; 하게 되면 i가 직접 caller에게 전달되는 것이 아니라
i의 사본이 전달됩니다. 뭐 i가 단순하게 int 또는 char 라면 직접 전달
되는 것이나 사본이 전달되는 것이나 별 차이가 없어보이기는 합니다만,
예전에 Turbo Assembler 뭐라는 책이 있었는데 어셈블러로 C와 인터페이스
하는 내용이 있어서 본적이 있었죠. C, 적어도 Turbo C에서는 함수가
int를 리턴하면 그 값을 AX 레지스터에 담아서 리턴합니다. 위에서 i를
리턴한다면 그 i는 실제로 스택에 있지만 리턴하기 전에 스택에 있는 i값을
AX로 '복사'한 후 이 AX를 리턴하는 것이죠. (물론 그 순간에 스택에 있는
i값은 사라집니다.) AX 하나에 담지 못하는 LONG 같은 경우에는 AX:BX 인지
AX:DX인지 잘 기억은 안나지만 하여튼 두개의 레지스터를 사용해서
리턴한다고 합니다. 더불어 레지스터로는 도저히 담을 수 없는 구조체 같은
것은 AX:DX에 구조체의 주소를 담아서 리턴한다고 되었던 기억이 있네요.
그때는 별로 그럴 일이 없어서 깊게 생각하지 않았는데 오늘 님의 질문을
보고 궁금해서 VC++로 테스트해봤습니다.
디버그 모드에서 어셈으로 변환된 main()함수는 다음과 같습니다.
잘 보시면 initA를 호출하기 전에 무언가 스택에 집어넣는 것을 볼 수 있네요.
그리고 호출을 끝낸 후에 리턴값을 소스 포인터로 해서 임시 버퍼에 복사를
하네요.
이 모든 것이 끝난 다음에서야 비로소 a로 아까 복사한 데이터를 다시
복사하는 군요.
PART3에서 a로 복사되는 데이터는 PART2에서 init 함수의 리턴값으로
넘겨준 EAX가 가르키는 버퍼에 있던 값입니다. 이 버퍼의 실제 값은
main함수의 스택에 있는 160바이트에서 -96(=$T578) 입니다. 이
값은 main 함수가 init를 호출하기 전에 넘겨줬던 값이죠. (실제로
init 쪽에서 어떻게 작업하는지에 대한 ASM 코드는 생략합니다. 글이
길어져서... 직접 확인해보세요. ^^;)
간단히 설명하면 구조체를 리턴하는 함수일 경우에는 caller가 리턴할 때
구조체를 임시로 보관할 버퍼를 알려준다는 얘기입니다. callee는 a를 초기화
한 후에 리턴하기 위해서 a 값을 (스택이 아닌) 임시 버퍼에 복사를 하고
그 버퍼의 포인터를 EAX를 사용해서 리턴합니다. caller는 이 값을 받아서
그 버퍼로부터 다시 자신의 임시 버퍼로 복사를 하고, 자신의 임시 버퍼에서
최종 목적지인 로컬 변수 a로 복사를 합니다. 다음과 같은 작업이 되겠죠.
방금 C++로 클래스를 리턴할 때는 어떨까 해봤는데 (동일한 코드에서
typeA를 struct에서 생성자를 가진 class로 변경했습니다.) 한번의 생성과
두번의 복사가 일어나는 군요. 결과적으론 위 코드와 개념상으로 크게 다른
것이 없어보입니다.
아, 물론 이것은 VC++ 6.0을 사용해서 디버그 모드에서 컴파일한 결과라는
것을 다시 한번 말씀드립니다. 다른 컴파일러나 릴리즈 모드에서 컴파일한
것과는 차이가 있을 수 있겠죠.
별것 아닌거 가지고 장황하게 설명했군요. 늦은 밤에 기나긴 문서 작성하기
싫어서 시작한 짓이... -.-; 도움되셨음 합니다.
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
재미없는 일은 하지 않겠다는 인간 쓰레기. ㅡ,.ㅡ;;
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
컴파일옵션을 디버그모드를 사용했을때는 아마 지역변수가리턴되어도 값은
컴파일옵션을 디버그모드를 사용했을때는 아마 지역변수가
리턴되어도 값은 보존되지만... 디버그옵션을 없애고 컴파일하면,
변수가 보존이 안됩니다.
하지만, 컴파일러 종류에 따라 다르게 나올거같네요.
<변수 i 의 값 리턴>[code:1]#include
<변수 i 의 값 리턴>
<변수 i의 주소 리턴>
지역 변수인 i가 스택 상에서 사리질 경우 잘못되는 것은
i의 주소를 리턴했을 경우겠죠^^
메모리 상에서 사라졌는데 그 주소를 사용하려니...
하지만 값을 리턴하는 경우는 상관없습니다..^^
===================================================
중요한건 얼마나 아느냐가 아니라 그것에 대한 열정이다.
요지는....지역변수는 리턴하지않는게 바람직하겠죠...
요지는....
지역변수는 리턴하지않는게 바람직하겠죠...
댓글 달기