로컬 변수의 주소 리턴
글쓴이: wakeup / 작성시간: 목, 2008/07/24 - 2:57오후
몇일 전 회사 면접보는 데 간단한 필기 테스트를 했습니다.
몇줄의 코드를 주고 잘못된 부분을 설명하라는 테스트였습니다.
코드가 잘못되었다고 생각이 드는데, 집에와서 해보니 정상적으로 동작이 되더라고요,
제가 잘못알고 있는건지..
코드는 아래와 같습니다.
int *sum(int a, int b) { int c = a + b; return &c; } int main() { int r = *sum(1,2); printf("%d\n",r); return 0; }
전 쓰레기 값이 나올줄 알았는데, 3이 출력되더군요..
제가 잘못알고 있는건가요?
Forums:
쓰레기가 안나온건
쓰레기가 안나온건 운이 좋아서 그런거 같은데요..
스택에 다른 내용이 들어가면 쓰레기가 들어갈거 같습니다만..
누구냐 넌?
쓰레기 값이 나올 수 있습니다.
해석: 자기가 짤 때 잘 돌아갑니다.
팀장이 볼 때 잘 돌아갑니다.
전체회의때도 잘 돌아갑니다.
QA가 해볼 때도 잘 돌아갑니다.
고객 사이트에 들어갑니다.
드디어! 쓰레기값이 나옵니다.
전체 시스템이 안 돌아갑니다.
전 팀원이 사흘간 밤샙니다.
원인이 밝혀집니다.
짤립니다.
바이바이~~~~~
* 버전관리 툴을 사용하지 않는 막장회사의 경우 누가 했는지 밝혀내지 못해서 안 짤릴 수도 있습니다. -.-
잘못된 코드입니다.
architecture에 따라서 다른 결과를 얻을 수도 있습니다. x86의 경우에는 해당 함수가 thread로 돌아가지
않으며 컴파일러 최적화를 하지 않고 반환 받은 포인터 참조가 다른 함수 호출 이전까지만 수행된다는 가정하에서 유효한 값을 얻을 수 있습니다. (현존하는 x86용 컴파일러가 stack 영역을 다루는 방법이 동일하게 되어 있어서 그렇습니다)
결론은 항상 '절대 사용하면 안되는 코드'라는 것입니다.
int *c = sum(1, 2);
int *c = sum(1, 2);
printptrval(c); // void printptrval(int *ptr) { printf("%d", *ptr); }
마치 저건 대형 클래스를 const ... &로 주고받으면 수행이 빨라진다고 해서
const BigClass &operator*(const BigClass &rhs) { return BigClass(this->test * rhs.test); }
하는 꼴이로군요.
--
임수서룬뫼 윤희수 {cppig1995/돼지군}
Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.
제 주변분이 그렇게 했다 피봤습니다.
실제 피를 본건 아니고... ^^;;;;;
윈도우에서 그렇게 된다고 유닉스에서 소스 그대로 가지고 가서 돌렸다가...
3일간 디버깅... ㅡ.ㅡ;;;;;
결국 지역변수 주소를 리턴한게 화근이었습니다.
이게 참 찾기 힘든에러죠
위와 같이 간단한 소스에서는 금방 찾겠지만.( 위의 경험이 없다면 헤멜수도 ^^)
방대한 소스에서는 미칩니다.
지역변수의 주소를 리턴하는 실수는 조심하세요
cats96님 말씀에 절대
cats96님 말씀에 절대 공감입니다. 간단한 소스야 바로 눈으로도 확인가능하고, debugger로 돌려도 바로 찾을 수 있지만, 소스의 양이 몇천에서 몇만으로 가게 되면, 이건 SIGSEGV도 아니라서 어디서 어떻게 바뀌는지 더더욱 찾기 힘들죠..
------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.
------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.
int c를 static으로
int c를 static으로 선언하면 어떻게 될까요?
singletone을 구현할때
singletone을 구현할때 지역변수를 static으로 선언해서 리턴하는 경우를 볼수 있습니다.
따라서, static를 붙이면 전역변수와 동일한 영역에 생성하기 때문에,
리턴해도 유효한 번지라고 할 수 있습니다.
다만, 여러군데에서 그 번지를 수정하는 경우에 버그가 발생하면,
전역변수를 사용하는 경우만큼 찾기가 어려울것 같습니다.
에러가 나도 전혀 엉뚱한 에러가 날 수도 있습니다.
X Window System 프로그램에서 저런 코드를 본 적이 있는데,
메모리 에러가 나는 것이 아니라 XtCreateShell need not NULL parent 인지 뭐 그런 에러가 나더군요.
어디서 저런 코드를 쓰느냐에 따라서 이렇게 황당한 경우도 있으니
절대 저렇게 사용하지 않는게 최선이겠죠.
저런 코드 적발시 작성자를 응징~
ㅋㅋ...다운 안된게 다행
뭐 플랫폼에 따라서 저런 소스코드 하나 때문에 전체 프로그램이 다운되는 경우가 있습니다.
위의 코드를 돌려보았습니다.
return_local_val.c 파일을 만들고 컴파일 해 보았습니다.
결과값은 3이라고 나오기는 하지만
gcc에서의 warning을 무시하면 안되겠군요
---------------------------------------------
리눅스가 싫다 우분투가 좋다
---------------------------------------------
---------------------------------------------
git init
git add .
git commit -am "project init"
---------------------------------------------
오늘도 많이
오늘도 많이 배웠습니다...
좋은 하루 되세요!!
좋은 하루 되세요!!
madman93님
madman93님 GCC 버전 몇인가요?
GCC에서 저런것도 워닝으로 잡아주다니 좋네요 ㅋㅋ
근데 전 워닝은 잘 패스하는 스탈이라...
워닝도 눈여겨 봐야겠네요
gcc version
다른 버전에서는 안 보일수 있나 보군요!!!!
---------------------------------------------
svn + trac + my project --> success ???
---------------------------------------------
---------------------------------------------
git init
git add .
git commit -am "project init"
---------------------------------------------
댓글 달기