함수 별칭 관련 질문입니다.
글쓴이: zasxer / 작성시간: 금, 2017/11/24 - 1:03오전
"함수별칭"을
보통 같은 매개변수를 가진 함수를 대체하기 위해 쓰는 거로 알고 있는데 (아래와 같이)
#include "stdafx.h" #include <stdio.h> typedef int(*pf)(int, int); int add(int a, int b) { return a + b; } int main(void) { pf pp; pp = add; printf("%d\n", pp(3, 4)); return 0; }
근데 sighander_t를 선언하고
sighander_t를 변수처럼 사용하는데 무슨 의미일까요???
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
.
sighandler_t signal(int signum, sighandler_t handler);
Forums:
C언어 문법을 따져 보면, "함수 별칭"이라는 게
C언어 문법을 따져 보면, "함수 별칭"이라는 게 특별히 따로 있지는 않습니다.
주어진 코드는 그저 typedef를 이용하여 함수 포인터 타입의 별칭을 만들고 사용했을 뿐입니다.
C언어 문법에 충분히 익숙해지기 전에는 위와 같은 용법을 이해하기 쉽지 않습니다.
하지만 일단 시도해 봅시다.
위 코드에서 선언한 pp는 사실 아래와 같이 선언한 것과 같은 의미입니다.
이 때 pp는 "int 타입 매개변수를 두 개 받고 int를 받는 함수 타입"에 대한 포인터가 됩니다.
보시다시피, add가 바로 그런 함수 타입이지요.
int 타입 변수의 주소를 int 포인터에 담을 수 있듯, 위와 같은 함수 포인터는 add의 주소를 담을 수 있는 것입니다.
즉 아래와 같이 쓸 수 있는 것이지요:
그런데 함수 포인터에는 좀 특이한 점이 있습니다.
보시다시피 i와 p는 뚜렷한 차이가 있는 반면, 왠지 add와 pp는 대개의 경우 서로 바꿔 쓸 수 있는 것처럼 보입니다. 이게 바로 종종 "함수 별칭"이라고 불리는 이유이지요.
사실 이게 가능한 건 C언어의 조금 자명하지 않은 규칙들 때문입니다:
(1) C언어에서 함수 타입을 가진 표현식(function designator 라고 합니다.)은 일부 예외 케이스를 제외하고는 곧바로 그 함수에 대한 포인터로 변환됩니다.
pp = add
라고 쓰면, add 앞에 &를 붙이지 않아도 자동으로 add 함수의 주소가 pp에 담기게 된다는 말이지요.예외가 딱 셋 있는데, sizeof, _Alignof, 그리고 unary &의 operand로 쓰이는 경우입니다. 근데 함수 타입에 sizeof이나 _Alignof를 적용하는 건 문법 위반이라, 실제로 사용되는 예외 케이스는 딱 하나뿐이라고 볼 수 있겠네요.
위 예외에 따라 &를 적용하기 전의 add는 함수 타입을 유지하므로
pp = &add
이 컴파일 되는 것입니다.(2) 함수 호출 구문 f(...)에서 f는 사실 함수 타입 표현식이 아니라 함수 포인터 타입 표현식을 받습니다. 그런데 왜 함수 타입 표현식 add를 이용해서
add(3, 4)
를 호출할 수 있느냐고 묻는다면, (1)을 보세요.아무튼, 여기까지 이해하셨다면 이제 더 이상 signal의 매개변수 형식이 의문스럽지 않을 겁니다.
typedef를 걷어 내고 나면 결국 아래와 같을 뿐이죠
즉, int 타입 매개변수 하나(signum), 그리고 "int를 받고 반환값이 없는 함수 포인터" 하나(handler)를 받는 것입니다. signal syscall의 용도를 알고 계신다면, 당연히 해당 signal이 왔을 때 호출할 함수를 받는다는 것을 알 수 있겠지요.
... 답변이 길어졌습니다만, 원래 함수 포인터는 좀 복잡하고, typedef로 함수 포인터 별칭을 만드는 건 조금 더 복잡해서요. 설명이 부족했다면...
https://dojang.io/mod/page/view.php?id=601
답글 감사합니다.
아래 매개변수가 의미하는 바가 무엇인지 알게 되었습니다.
sighandler_t가 함수 별칭으로 쓰여서
라고 하셨는데
앞의 반환하는 sighandler_t도 함수 별칭을 쓰고 있습니다.
앞의 sighandler_t 반환에 대해 어떻게 해석하면 좋을까요?
아, 귀찮아서 슬쩍 설명 안 하고 넘기려고 했는데
아, 귀찮아서 슬쩍 설명 안 하고 넘기려고 했는데 지적하시는군요. :(
별 거 아닙니다. int 포인터를 반환하는 함수가 있을 수 있으면,
함수 포인터를 반환하는 함수도 있을 수 있죠.
signal 함수도 마찬가지로 함수 포인터를 반환하는 함수입니다.
함수 원형을
typedef
없이 나타내면 아래와 같습니다:signal syscall은 새 signal handler(의 함수 포인터)를 설정하면서 이전의 signal handler(의 함수 포인터)를 반환하므로, 이런 형식이 불가피한 것이죠.
근데 이런 식으로 써 두면 누가 한 눈에 알아보겠어요?
딱 보다시피 굉장히 비직관적인 형태의 문법이므로 웬만해서는
typedef
를 쓰는 게 좋습니다:참고로 함수를 호출해서 반환받은 함수 포인터를 바로 연달아 호출하는 짓도 가능합니다:
함수포인터를반환하는함수포인터를반환하는함수포인터를반환하는함수:
배우고 갑니다.
진짜 감사합니다.
함수 자체를 반환한다고 생각치도 못했는데...
엄청 잘하시네요. 부러워요ㅠ
와 진짜 또 한번 존경합니다.
댓글 달기