음, C의 모든 기능이 포인터이며 다른 포인터에 대한 포인터를 캐스팅 할 수 있다는 사실을 악용하는 진정한 하드 코어 트릭이있다. 컴파일러가 암시 적 캐스트에 대해 오류를주지 않았을 때 원본 코드를 작성 했으므로 함수를 변환해야한다는 것을 알게되었습니다. 그것은 콜백 함수를 가변 개수의 인수를 가진 함수로 캐스트한다는 것입니다. 그러나 동시에 호출 함수는 10 개의 인수를 갖는 함수로 캐스트되며, 그 중 일부는 제공되지 않습니다. 특히이 마지막 단계는 까다로워 보이지만 이전에 printf에 잘못된 인수를 지정하고 컴파일 한 후에 만 보았습니다. 이것이 va_start/va_end가 실행하는 것일 수도 있습니다. 코드는 데이터베이스의 모든 요소에 대해 사용자 정의 작업을 수행하기위한 사실이지만,뿐만 아니라 상황에 사용될 수 있습니다 :
#include <stdio.h>
typedef int (*INTFUNC)(int,...);
typedef int (*MAPFUNCTION)(int [], INTFUNC, ...);
//------------------CALLBACK FUNCTION----------------
static int callbackfunction(int DatabaseRecord,int myArgument,int *MyResult){
if(DatabaseRecord < myArgument){
printf("mapfunction record:%d<%d -> result %d+%d=%d\n",DatabaseRecord,myArgument,*MyResult,DatabaseRecord,*MyResult+DatabaseRecord);
*MyResult+=DatabaseRecord;}
else{
printf("mapfunction record:%d<%d not true\n",DatabaseRecord,myArgument);
}
return 0; // keep looping
}
//------------------INVOCATION FUNCTION---------------
static int MapDatabase(int DataBase[], INTFUNC func, void* a1, void* a2, void* a3, void* a4, void* a5, void* a6, void* a7, void* a8, void* a9)
{
int cnt,end;
int ret = 0;
end = DataBase[0]+1;
for(cnt = 1;cnt<end;++cnt){
if(func(DataBase[cnt], a1, a2, a3, a4, a5, a6, a7, a8, a9)) {
ret = DataBase[cnt];
break;
}
}
return ret;
}
//------------------TEST----------------
void TestDataBase3(void)
{
int DataBase[20];
int cnt;
int RecordMatch;
int Result = 0;
DataBase[0] = 19;
for(cnt = 1;cnt<20;++cnt){
DataBase[cnt] = cnt;}
// here I do the cast to MAPFUNCTION and INTFUNC
RecordMatch = ((MAPFUNCTION)MapDatabase)(DataBase,(INTFUNC)callbackfunction,11,&Result);
printf("TestDataBase3 Result=%d\n",Result);
}
같은 기능이 완벽하게 va_start를/va_end의를 사용하여 작성할 수 있습니다. 그것은 일을하는 더 공식적인 방법 일지 모르지만 나는 사용자 친화적이지 못하다. 콜백 함수가 인수를 디코딩해야하거나 콜백 함수가 가질 수있는 모든 인수 조합에 대해 호출 함수 내에 switch/case 블록을 작성해야합니다. 이것은 인수의 형식을 제공해야한다는 것을 의미합니다 (printf가하는 것처럼). 또는 모든 인수가 동일해야하며 인수의 개수를 제공해야하지만, 각 인수에 대한 사례를 작성해야합니다. 인수의. 다음은 콜백 함수는 인수를 디코딩하는 예는 다음과 같습니다
#include <stdio.h>
#include <stdarg.h>
//------------------CALLBACK FUNCTION----------------
static int callbackfunction(int DatabaseRecord,va_list vargs)
{
int myArgument = va_arg(vargs, int); // The callbackfunction is responsible for knowing the argument types
int *MyResult = va_arg(vargs, int*);
if(DatabaseRecord < myArgument){
printf("mapfunction record:%d<%d -> result %d+%d=%d\n",DatabaseRecord,myArgument,*MyResult,DatabaseRecord,*MyResult+DatabaseRecord);
*MyResult+=DatabaseRecord;}
else{
printf("mapfunction record:%d<%d not true\n",DatabaseRecord,myArgument);
}
return 0; // keep looping
}
//------------------INVOCATION FUNCTION---------------
static int MapDatabase(int DataBase[], int (*func)(int,va_list), int numargs, ...)
{
int cnt,end;
int ret = 0;
va_list vargs;
end = DataBase[0]+1;
for(cnt = 1;cnt<end;++cnt){
va_start(vargs, numargs); // needs to be called from within the loop, because va_arg can't be reset
if(func(DataBase[cnt], vargs)) {
ret = DataBase[cnt];
break;
}
va_end(vargs); // avoid memory leaks, call va_end
}
return ret;
}
//------------------TEST----------------
void TestDataBase4(void)
{
int DataBase[20];
int cnt;
int RecordMatch;
int Result = 0;
DataBase[0] = 19;
for(cnt = 1;cnt<20;++cnt){
DataBase[cnt] = cnt;}
RecordMatch = MapDatabase(DataBase,callbackfunction,2,11,&Result);
printf("TestDataBase4a Result=%d\n",Result);
Result = 0;
RecordMatch = MapDatabase(DataBase,callbackfunction,0,11,&Result); // As a hack: It even works if you don't supply the number of arguments.
printf("TestDataBase4b Result=%d\n",Result);
}
매개 변수 수가 다른 함수를 미리 모르는 경우, 콜백을 호출 할 코드의 인수로 호출에 전달할 값은 어디에서 얻습니까? –
lambdas가 필요합니다. 컴파일러가 아직 그들을 지원합니까? 그렇지 않다면 부스트의 피닉스 게으른 기능을보십시오. –
먼저 매개 변수를 어떻게 가져 옵니까? –