본문 바로가기
SW/C,C++

[C/C++] 콜백함수의 인자로써 void 포인터

by FastBench 2024. 4. 21.
반응형

콜백함수의 인자로써 void 포인터

콜백함수에 대한 그림을 그려달라니, 이런걸 그려주네요 ㅋㅋ

Intro

지난 게시글에서, 이중포인터와 void 포인터에 대해 간략하게 다뤘다.

https://microelectronics.tistory.com/54

 

[C/C++] 이중포인터와 void 포인터

이중포인터와 void 포인터 문자열배열은 이중포인터이다 아래와 같이 문자열 배열이 있고, 해당 문자열배열의 주소를 void 포인터에 초기화시켰다고 가정해보자. char* arr[] = {"banana", "apple"}; void* vr

microelectronics.tistory.com

또한 콜백함수에 대해 왜/언제 쓰는지를 알아보았다.

https://microelectronics.tistory.com/46

 

[C/C++] 콜백함수 (Callback Function)

콜백 함수란? 콜백 함수는 다른 코드의 인자로 전달되어, 그 코드에 의해 어느 시점에 호출되는 함수인데 특히 비동기적 작업, 이벤트 리스닝, 또는 특정 조건 하에서 실행되어야 할 코드 조각을

microelectronics.tistory.com

이를 바탕으로 단일 sort 함수로 다양한 데이터타입을 처리하는 예제를 다뤄보고자 한다.

타입에 맞는 sort 함수

내가 라이브러리를 만드는 개발자로서, sort 와 관련된 라이브러리를 만든다고 가정해보자.

이 경우에는, 여러 데이터 타입에 대응하는 각각의 sort 함수를 생성하는 대신, 사용자가 제공하는 비교 함수를 사용하여 유연하게 작동하는 단일 sort 함수를 설계하는 것이 효율적일 것이다.

 

이 접근 방식에서 sort 함수는 비교 로직을 처리할 수 있는 '함수 포인터'를 인자로 받는다.

이 함수 포인터는 사용자가 정의한 비교 함수를 가리키며, 이 함수는 sort 함수 내에서 데이터 항목들을 비교하는 데 사용된다.

 

이렇게 하면, 라이브러리 사용자는 자신의 데이터 타입에 맞는 비교 로직을 작성하여 이를 sort 함수에 전달할 수 있다.

라이브러리 제작자는 이 비교 함수의 프로토타입(즉, 함수의 반환 타입과 매개변수 타입)만 정의해두면 되고,
사용자는 자신의 데이터 타입에 맞는 비교 함수를 정의하고, 이 함수를 sort 함수에 콜백으로 전달하면 된다.

 

결과적으로, 단 하나의 범용 sort 함수를 제공함으로써 다양한 데이터 타입과 상황에 적합하게 쓰일 수 있는 매우 유연한 정렬 라이브러리를 만들 수 있다.

sort 함수 예시

아래는 주어진 배열에 대해 선택정렬을 실행하는 함수의 예시이다.

void sort(void* arr, int len, int typesize, bool (*cmp)(void* a, void *b)){
    void* tmp = (void*)malloc(typesize);
    for (int i = 0; i < len - 1; i++){
        for ( int j = i; j < len; j++){
            if ( cmp ( (char*)arr + i*typesize, (char*)arr + j*typesize)){
                memcpy(tmp, (char*)arr + i*typesize, typesize);
                memcpy((char*)arr + i*typesize, (char*)arr+j*typesize, typesize);
                memcpy((char*)arr + j*typesize, tmp, typesize);
            }
        }
    }
    free(tmp);
}

비교를 하는 콜백함수로 cmp 를 마련했고, cmp 는 아래와 같이 정의 가능하다.

주목해야 할 부분은, 어떤 데이터 타입이 올지 모르기때문에 제네릭 포인터인 void 포인터를 비교함수의 인자로 주어줘야 한다는 것이다.

 

각 비교함수에서는 void 타입 포인터를 실제 데이터타입에 맞게 캐스팅을 해주어야 한다.

지난 게시글에서 문자열배열은 이중포인터라고 다뤘다. 그에 맞게 char** 타입으로 캐스팅을 해줘야 한다는 것을 꼭 이해하고 넘어가야 한다.

bool compare_string(void* a, void*b){
    char* str1 = *(char**)a;
    char* str2 = *(char**)b;
    return strcmp(str1,str2) > 0;
}

bool compare_int(void* a, void* b){
    if (*(int*)a > *(int*)b) return 1;
    else return 0;
}

 

 

C++ - Template

C++ 에서는 다양한 데이터타입에 대한 코드 중복을 줄이기 위해, template 이란 키워드를 제공한다.

template<typename T>
void sort(T* arr, size_t len) { 
    T tmp;
    for (size_t i = 0; i < len; i++) {
        for (size_t j = i + 1; j < len; j++) {
            if (arr[i] > arr[j]){
                tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
            }
        }
    }
}

코드도 훨씬 간결하고, 가독성 있게 작성할 수 있다.

 

이게 가능한 이유는 컴파일러가 컴파일타임에 여러 데이터 타입에 해당하는 sort 함수를 자동으로 만들어 주기 때문이다.

 

출력하는 함수도 마찬가지이다. 템플릿을 사용하면 C와는 다르게 단일 함수로 어떠한 배열이 오더라도 모두 처리할 수 있다.

반응형

댓글