Ну, есть настоящий хардкорный трюк, который использует тот факт, что в 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);
}