Proven C BookEnglish GitHub

21 함수 사용 — 부르는 법

먼저 알아야 할 것

20장 수식과 상수 · 수식은 값이 된다
19장 프로그램의 구조 · 함수라는 이름의 덩어리

돌아보기

20장 끝에서 “함수를 부르는 것 자체가 수식이고, 따라서 값이 된다”고 했다. 그러면 printf("%d\n", 2 + 3 * 4) 안의 수식 2 + 3 * 4가 계산된 값 14는 — 정확히 어디로 가는 것인가?

답. 함수의 입으로 들어간다. 함수를 부를 때 괄호 안에 적는 수식들의 값이 그 함수에게 재료로 전달되고, 함수는 그 재료로 제 일을 한 뒤 결과 값을 내놓는다. 재료를 인자, 결과를 반환값이라 부른다 — 이 두 낱말이 이 장의 전부다.

이 장의 필요성과 맥락

값을 적을 줄 알게 되었으니 남이 만든 일꾼을 부릴 차례다. 만드는 법(24장)을 미루고 부르는 법을 먼저 놓는 것이 이 책의 순서다 — 헬로 월드의 심장이 호출 한 줄이기 때문이다. 그리고 실무에서도 함수를 정의하기 전에 훨씬 많이 부른다.

이 장이 끝나면

함수를 만드는 법은 아직 멀었다(24장). 이 장은 부르는 법이다 — 호출, 인자, 반환값이라는 세 낱말을 익히고 나면, 헬로 월드의 심장 printf("안녕, 세상!\n"); 이 완전한 문장으로 읽힌다. 남이 만든 일꾼을 부려 쓰는 것 — 프로그래밍의 절반은 사실 이것이다.

이 장에서 답할 질문

  1. 버려도 되는 값이라면 애초에 왜 돌려주는가?
  2. abs는 항상 양수를 돌려주는가? 절댓값이니 당연할 것 같은데.

21.1 호출 — 이름을 부르면 일꾼이 뛴다

함수는 이름 붙은 일꾼이다. 어딘가에 일하는 방법(몸통)이 만들어져 있고, 우리는 이름만 부르면 된다. 부르는 문법은 이미 눈에 익었다:

이름(재료1, 재료2, ...)

이것이 호출(call)이다. 호출이 실행되는 순서는 이렇다 — ① 괄호 안의 수식들이 먼저 평가되어 값이 되고, ② 그 값들이 함수에게 전달되며, ③ 함수의 몸통이 실행되고, ④ 함수가 내놓은 반환값이 호출 자리의 값이 된다. 마지막 항목이 20장의 복선 회수다: 호출은 수식이다 — 호출이 적힌 자리는, 실행이 끝나면 반환값 하나로 바뀐다고 읽으면 된다.

호출이 수식이므로, 호출을 호출의 재료로 넣을 수도 있다. 시연한다 — abs는 표준 라이브러리(standard library)의 일꾼으로, 정수 하나를 받아 그 절댓값을 돌려준다(<stdlib.h> 도구 상자에 산다 — 그래서 #include가 하나 더 붙었다).

examples/ch21/call.c

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    printf("%d\n", abs(2 - 10));  /* 호출의 결과가 다시 호출의 재료가 된다 */
    return 0;
}

실행 결과

8

읽는 순서 그대로다 — 안쪽 수식 2 - 10이 먼저 8이 되고, 그것이 abs의 재료로 들어가 반환값 8이 되고, 그 8이 다시 printf의 재료가 되어 찍혔다. 안에서 바깥으로, 값이 릴레이된다 — 수식과 호출이 겹겹이 쌓이는 C 코드를 읽는 기본 독법이다.

21.2 반환값 — 쓰거나, 버리거나

모든 호출은 값이 된다고 했다. 그러면 헬로 월드의 printf("안녕, 세상!\n"); 에서 반환값은 어디로 갔는가.

버려졌다 — 그리고 그것은 합법이다. 수식 뒤에 세미콜론을 찍으면 “수식을 평가하고, 값은 버리는” 문장(수식문)이 된다. printf도 반환값이 있다(찍은 글자 수를 돌려준다). 다만 우리는 대개 찍는 부수 효과가 목적이고 글자 수는 관심 밖이라, 값을 버리는 것이다. “함수를 부르는 문장”이란 사실 “호출 수식 + 값 버리기”였던 셈이다.

문. 버려도 되는 값이라면 애초에 왜 돌려주는가?

답. 쓰는 사람이 따로 있기 때문이다. 같은 일꾼이라도 부르는 쪽의 사정에 따라 결과가 필요할 수도, 부수 효과만 필요할 수도 있다 — 함수는 일단 결과를 내놓고, 쓸지 버릴지는 부르는 쪽이 정한다는 것이 C의 분업이다. 다만 이 관대함에는 그림자가 있다 — 반환값이 “성공했는지” 를 알리는 함수라면, 버리는 순간 실패를 놓친다. 오류를 값으로 알리는 C의 방식과 “버리면 안 되는 반환값”의 이야기는 51장의 주제다.

문. abs는 항상 양수를 돌려주는가? 절댓값이니 당연할 것 같은데.

답. 거의 항상 — 그런데 정확히 한 곳에 함정이 있다. 7장에서 2의 보수의 유일한 비대칭을 배웠다: 가장 작은 음수(-128, 32비트라면 약 −21억)의 짝이 되는 양수가 없다. 그러면 그 수의 절댓값을 물으면 어떻게 되는가 — 담을 그릇이 없으므로, 계약 밖(정의되지 않은 동작)이다. “당연히 되겠지”의 딱 한 칸 바깥에 함정이 있는 것 — 7장의 비대칭이 실제 함수의 사용 설명서에까지 흔적을 남긴 사례다. 이런 경계 사냥은 52장의 주특기가 된다.

21.3 표준 라이브러리 — 미리 만들어진 일꾼들

printfabs도 우리가 만들지 않았다. C를 설치하면 따라오는 표준 라이브러리 — 16장의 링크 단계에서 우리 프로그램에 이어지던 바로 그 꾸러미 — 의 일꾼들이다. 도구 상자(<stdio.h>, <stdlib.h> 등)마다 쓸 수 있는 일꾼의 명단(선언)이 들어 있고, #include로 명단을 가져오면 그 상자의 일꾼들을 부를 수 있게 된다.

표준 라이브러리에 어떤 상자가 있고 무엇이 들었는지는 62장에서 얼개를 펴고 훑는다. 지금 챙길 것은 감각 하나다 — 프로그래밍의 절반은 남이 만든 함수를 부르는 일이다. 잘 만들어진 일꾼을 알아보고 바르게 부리는 것이 코드의 절반을 결정하고, 그래서 이 책의 후반(43장)에서 “어떤 일꾼을 쓸 것인가”가 다시 큰 주제가 된다.

이제 헬로 월드에서 남은 칸은 둘뿐이다 — printf의 따옴표 안 서식이 정확히 어떻게 동작하는지(다음 장), 그리고 int main(void)return 0의 정체(제5부). 다음 장에서 출력을 정면으로 다루며 제4부의 목표에 바짝 다가선다.