함수포인터 문제..
글쓴이: 나빌레라 / 작성시간: 목, 2003/06/05 - 1:47오후
과연 이게 함수포인터에 관한 문제인지조차 의심스럽지만 아무래도 함수 포인터에 관련된 문제 같아서 질문드립니다.
후배가 물어본건데, 저도 답을 몰라, 답을 못했줬거든요...(아..쪽팔려...)
근데 저도 궁금해서, 고수분들께 물어봅니다.
#include <stdio.h> void f(void); void g(void); void h(void); int main(void) { (*f)(); return 0; } void f(void) { printf("Hello from f().\n"); (((*g)))(); } void g(void) { printf("Hello from g().\n"); (*(*(*h)))(); } void h(void) { printf("Hello from h().\n"); }
이런 소스 인데... 함수포인터에 저렇게 *을 계속 붙이면 포인터가 가르치는 주소의 주소의 주소의 값을 찾아가기때문에 잘못된 값이 나오는거 아닌가요?
그런데 결과는..
Hello from f(). Hello from g(). Hello from h().
이렇게 잘 만 나옵니다...
그리고 마지막 함수에
(*(*(*h)))();
를
(*(*h))();
라고 해도 에러 없이 결과 잘 나오네요..
대체 이유가 뭘까요?
함수포인터를 사용해 개발해본 경험도 있는데, 막상 저렇게 누군가가 물어보니,
이유를 딱 설명하기 난감해지네요...
함수포인터의 괄호밖 *은 리턴값인가... 하는 생각도 들고...[/code]
Forums:
명시적 표현과 함시적 표현..
함수포인터의 명시적 표현은 앞에 *를 붙이는 걸로 알고 있구요..
암시적으로 함수의 이름자체가 함수 포인터라고 알고 있습니다...
즉 함수 이름 앞에 *를 붙이는 것은 함수 포인터라는 것을 명시적으로 나타내기
위해 사용하는 것으로 알고 있습니다. h()라는 함수가 있을때
(*f)()이렇게 호출하는 것과 f()는 실행결과가 같죠..
(*(*f))() 와 (*f)()도 같은 논리로 하면 같죠 ..
그러므로 (*(*f))() 와 f()도 같다고 ;; 생각이 되네요 ..
서명 없음
[code:1]함수 이름 앞에 *를 붙이는 것은 함수 포인터라는 것을
함수의 이름이 암시적으로 함수 포인터라는건 알겠습니다.
그래서 f()와 (*f)() 가 같다는건 이해가 가는데,
그 앞에 * 또붙으면 마치 이중포인터 처럼
포인터의 포인터 아닌가요?
함수포인터만 앞에 *가 여러개 붙어도 무시하고 처리한다면,
C언어 자체의 포인터 변수 규칙이 일관성이 없어지는듯 한데요.
----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
(****************************(*f))()(*
(****************************(*f))()
(*(*f))()
(*f)()
위의 셋은 똑같은 곳을 호출합니다.
assemble 코드를 보니
Call @ILT + offset(f) 로 나오는군요.
compiler가 해석을 하는데 있어서의 문제인듯합니다.
이중 pointer혹은 다중 pointer로 잡지 않고
*뒤에 의미없는 문자열이 이어져있을때는 null offset과 같은 걸로 처리하는것 같군요..
평온하다~
그렇다면...
수고스럽게, 디스어셈블까지 해주셔서 너무 감사합니다.
그렇다면 결론은, 함수포인터에 있어서 만큼은, * 이 몇개이건 간에,
그냥 단순한 포인터 변수로 취급한다는 건가요?
(좋은건지..나쁜건지...)
----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
http://c-expert.uos.ac.kr/board/hclc_pos
http://c-expert.uos.ac.kr/board/hclc_post_board/ScB.cgi?process=disp_data&datanum=499
를 참고하시기 바랍니다. C 언어의 문법적 정의를 적용하면 나오는 당연한 결과입니다.
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
Re: 함수포인터 문제..
컴파일러가 컴파일시에 code optimizing을 행함으로 인해 복수개의 *가 생략되는걸로 알고 있습니다. 다음의 코드가 컴파일시 생략되는것과 마찬가지로...
for(int i=0; i < 10000; i++);
물론 코드 옵티마이즈 단계를 컴파일시에 명시하면 달라 집니다.
Re: 함수포인터 문제..
아니오. 다릅니다. 컴파일러의 옵티마이즈와는 상관없이 C언어 자체적인 정의에 의해 (*******func_ptr)(); 과 같은 코드를 허용합니다. 위의 전웅님께서 올리신 글을 잘 읽어보세요.
Re: 함수포인터 문제..
아 그렇군요. 지금까지 코드 옵티마이즈와 관련해서 생각을 했는데...
이번기회에 함수포인터에 대한 C언어에서의 정의를 자세히 알게 되었군요. 감사합니다. ^^.
그런데 정말 궁금한것은.... 해당 링크된 사이트에서도 나타나질 않는데...
왜 (******평선포인터)(); 와 같은 형태를 취하여 함수를 호출하는지는 안 나타나 있네요.
왜 저런 형태를 사용하죠? 식별자가 pointer to pointer to pointer.... 라 하더라도, 실제로 이런 자료형이 크게 유용한지도 의문이 듭니다...
Re: 함수포인터 문제..
현실적인 유용성은 없겠지만, 어떤 대상체의 데이터형이 실제로 pointer to
pointer to pointer to ... function 인 경우 반드시 위와 같은 수식을
사용해 최소한 poiner to function 이나 function 단계까지 지정해야 함수
호출을 할 수 있습니다.
해당 글에서 제가 인용한 책에 자세히 설명되어있지만, 이와 같이 이상한
형태의 함수 호출 수식이 허락되는 이유는 C 언어가 정의되는 과정에서
발생한 일종의 문법적 부작용이라고 보시면 됩니다. 예를 들어, 배열 첨자
연산인 a[i] 가 포인터 연산인 *((a) + (i)) 로 정의됨으로써 i[a] 라는
기형적 형태의 수식이 허락되는 것과 같은 이치입니다.
C 언어의 표준화 과정에서 함수 호출을 함수형의 function designator 가
아닌 함수 포인터에 적용되는 연산으로 정의하고, (마치 많은 문맥에서
배열이 포인터로 decay 하듯이) function designator 가 거의 대부분의
문맥에서 함수 포인터로 변환되는 것으로 정의함으로써 부작용으로 허락된
수식입니다.
함수 지정자가 아닌 함수 포인터에 함수 호출이 허락되도록 정의한 것은
표준화 이전의 다수의 existing practice 를 반영한 것이며 동시에 함수
포인터가 구조체 멤버 같이 보다 복잡한 문맥에 포함되어 있는 경우,
*(object->f()); 처럼 보기 싫은 수식보다 (마치 실제 함수인 것처럼)
간단한 형태인 object->f(); 로 쓸 수 있도록 허락하려는 의도입니다.
그 과정에서
같은 외관상 이상한 함수 호출 수식이 허락되었지만 현실적인 문제를
일으키지도 않고 마땅히 금지할 논리적 이유가 없기 때문에 i[a] 를
허락하듯이 그냥 허락하게 된 것 뿐입니다.
그럼...
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
댓글 달기