嗯,有一個真正的鐵桿把戲,利用這樣的事實,在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用來寫入。這可能是更正式的做事方式,但我覺得它不太方便用戶。要麼回調函數需要解碼其參數,要麼需要在調用函數中爲回調函數可能具有的每個參數組合寫入開關/大小寫塊。這意味着你必須提供參數的格式(就像printf一樣),或者你必須要求所有的參數都是相同的,你只需要提供參數的數量,但是你仍然必須爲每個數量寫一個case的論據。這裏是回調函數解碼參數爲例:
#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);
}
如果您使用不同數量的參數調用函數,以至於您事先不知道這些函數,那麼您會在哪些位置將值作爲參數傳遞給調用,以便調用回調? – 2009-12-03 23:49:53
您需要lambdas,您的編譯器是否支持它們?如果沒有,看看Boost的鳳凰懶惰功能。 – 2009-12-04 00:07:38
您如何首先獲取參數? – 2009-12-04 00:13:06