본문 바로가기

awesome-c Beginner 번역/Introduction to 'fun' C

<비공식 번역>awesome-c Beginner번역: function2.c

function2.c



/**

* This is an example of more complex function usage in C.

* Read structs.c before continuing.

*/


#include <stdio.h>



// Good reference:

// http://www.dirac.org/linux/programming/tutorials/function_pointers/



typedef struct {

    int legs;

    void (*sayName)(void);

} Animal;



void catSayName() {

    printf("I am a cat.\n");

}



void dogSayName() {

    printf("I am a dog.\n");

}



int sub(int a, int b) {

    return a - b;

}



int sum(int a, int b) {

    return a + b;

}



double sum_d(double a, double b) { return a + b; } // would fail if passed to operate: operate(sum_d, 1, 2)



int operate(int (*f)(int, int), int a, int b) {

    return f(a, b);

}



void do_nothing(void) {

    return;

}



int main() {

    Animal cat;

    cat.legs = 4;

    cat.sayName = catSayName;


    Animal cat1;

    cat1.legs = 4;

    cat1.sayName = catSayName;



    Animal dog;

    dog.legs = 3;

    dog.sayName = dogSayName;



    cat.sayName(); // I am a cat.

    dog.sayName(); // I am a dog.

    cat.sayLegs(cat.legs);



    int my_sum = operate(sum, 1, 2);

    printf("%d\n", my_sum); // Prints 3

    int my_sub = operate(sub, 11, 2);

    printf("%d\n", my_sub); // Prints 9



    do_nothing();

}



이번 함수는 다소 알아보기 어렵게 꼬아놨습니다.

일단 return;을 do_nothing()으로 만든 것...이 한번이라도 더 다른곳으로 분기한걸 보도록 하려는 교육자의 배려....인 것 같은데... 보는사람으로서는 귀찮(크흠)습니다.


먼저.. 구조체부터 살펴보겠습니다.

typedef struct {

int legs;

void (*sayName)(void);

} Animal;


내부에는 int형 변수 legs 다리 수 겠죠? 이건 별로 어렵지 않으니 넘어가고
다음 변수는 포인터인데, 함수포인터네요. 인자는 받지 않는 함수포인터입니다.

그러한 구조체를 Animal이란 이름으로 선언해뒀네요.



void catSayName() {

printf("I am a cat.\n");

}


void dogSayName() {

printf("I am a dog.\n");

}


이 함수들은 간단하게 고양이냐 동물이냐를 출력하는 함수입니다.

그런데 함수 형태를 살펴보니 구조체가 가진 이름의 형태와 유사성이 보입니다.

인자도 없구요. void 타입이구요. 뭔가 sayName에 넣게 생겨보입니다.



int sub(int a, int b) {

return a - b;

}


int sum(int a, int b) {

return a + b;

}


double sum_d(double a, double b) { return a + b; }


int operate(int (*f)(int, int), int a, int b) {

return f(a, b)

}


function.c에서 본 것과 비슷한 함수들입니다.

sub, sum은 간단하니 따로 말씀드리지 않아도 될 것입니다 :)


그 다음으로 넘가면 sum_d이라는 함수가 있습니다.

인자는 double형 2개, 내용은 인자 2개를 더하여 리턴, 그래서 반환형도 double입니다.

sum은 이미 있으니 double의 d를 따서 sum_d가 되었습니다.


operate라는 함수는 특이하게도 int (*f)(int, int)라는 인자를 받습니다.

(한줄로 다 파악할 때 어렵다면 문제를 분리하여 보면 한결 간단한해 질때가 많습니다.

이 경우도 그런 경우죠, 모든 인자를 한꺼번에 보려면 파악하기 어려울 수 있습니다만 하나씩 보면 이해가 간단합니다.)

이 인자는 함수포인터를 받습니다. 리턴형은 int, 인자는 2개이고 둘다 int형 이네요.

함수 포인터를 받고 나머지 두개의 인자를 함수포인터에 넣어 그 결과를 리턴합니다.



자 그러면 모든 함수를 다 확인하였으니, main함수를 순서대로 따라가서 예상되는 결과를 그려봅시다.


int main() {

    Animal cat;

    cat.legs = 4;

    cat.sayName = catSayName;


    Animal cat1;

    cat1.legs = 4;

    cat1.sayName = catSayName;



    Animal dog;

    dog.legs = 3;

    dog.sayName = dogSayName;



    cat.sayName(); // I am a cat.

    dog.sayName(); // I am a dog.

    cat.sayLegs(cat.legs);



    int my_sum = operate(sum, 1, 2);

    printf("%d\n", my_sum); // Prints 3

    int my_sub = operate(sub, 11, 2);

    printf("%d\n", my_sub); // Prints 9



    do_nothing();

}


Animal 구조체 cat을 선언하고

다리는 4개, 함수포인터에는 catSayName함수를 넣습니다.


또다른 구조체 cat1을 선언하고

다리는 4개, 함수포인터에는 catSayName함수를 넣습니다.


이번에는 Animal 구조체 dog를 선언하고

다리는 3개(음..? 3...개?), 함수포인터에는 dogSayName함수를 넣습니다.


이제 cat구조체 멤버 sayName, dog구조체 멤버 sayName을 각각 실행하고

음... cat구조체 멤버로 sayLegs를 실행...하는데

sayLegs란 함수가 어디있죠?


음...제작자 분께서 까먹은게 아닌가 싶습니다.

그러면 뭐 임의로 추가해봅시다.


구조체를 임시로 이렇게


typedef struct

{

int legs;

void (*sayName)(void);

void sayLegs(int legs)

{

printf("legs : %d\n", legs);

}

} Animal;


요 정도로 개편하면 동작할 수 있을 것 같습니다.

그러면 다리가 몇개인지도 보여주겠네요.


마지막은 sum, sub 함수를 함수포인터를 사용하여(위에서 언급한 operate함수) 결과를 출력합니다. 

operate(sum, 1, 2)는 sum(1, 2)와 같은 내용이고

operate(sub, 11, 2)는 sub(11, 2)와 같은 내용입니다.


다음은 pointers.c로 찾아뵙겠습니다.



출처1 : https://github.com/aleksandar-todorovic/awesome-c

출처2 : https://gist.github.com/eatonphil/21b3d6569f24ad164365