2016-07-07 3 views
2

Я хочу передать произвольную функцию, и это аргументы другой функции в С.Как передать функцию И переменный список аргументов другой функции в C?

Например, как приведенный ниже код (который, очевидно, не работает)

#include <stdio.h> 

void doit(int (*f)(...), char *fname, ...) 
{ 
    va_list argptr; 
    va_start(argptr, fname); 
    f(argptr) 
    va_end(argptr); 
} 

int func1(char *a, int b) 
{ 
    fprintf(stderr, "func1 %s %d\n", a, b); 
} 

int func2(char *a, int b, int c) 
{ 
    fprintf(stderr, "func2 %s %d %d\n", a, b, c); 
} 

int main(int argc, char **argv) 
{ 

    doit(func1, "func1", "blah", 10); 

    return 0; 
} 
+0

http://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work – user3605508

+0

Я понимаю, как работают основные указатели функций. Мой вопрос - посмотреть, можете ли вы передать переменные аргументы функции. Это теоретически возможно, потому что в конце дня аргументы просто передаются в стек. Я могу сделать это в ассемблере легко, задаваясь вопросом, есть ли трюк C, чтобы не сделать это, не прибегая к сборке. –

+0

Стандарт C не имеет права на стеки. И типичные ABI не используют только стек для передачи аргументов. – Olaf

ответ

5

Вам нужно va_list форвардеры своим функциям, если это вы хотите, чтобы они участвовали в такой схеме. Что-то вроде:

#include <stdio.h> 
#include <stdlib.h> 
#include <stdarg.h> 

void doit(int (*f)(va_list va), char *fname, ...) 
{ 
    va_list argptr; 
    va_start(argptr, fname); 
    f(argptr); 
    va_end(argptr); 
} 

int func1(const char *a, int b) 
{ 
    fprintf(stderr, "func1 %s %d\n", a, b); 
    return 0; 
} 

int func1_va(va_list va) 
{ 
    const char * a = va_arg(va, const char*); 
    int b = va_arg(va, int); 
    return func1(a,b); 
} 

int func2(const char *a, int b, int c) 
{ 
    fprintf(stderr, "func2 %s %d %d\n", a, b, c); 
    return 0; 
} 

int func2_va(va_list va) 
{ 
    const char *a = va_arg(va, const char*); 
    int b = va_arg(va, int); 
    int c = va_arg(va, int); 
    return func2(a,b,c); 
} 

int main(int argc, char **argv) 
{ 

    doit(func1_va, "func1", "blah", 10); 
    doit(func2_va, "func2", "blahblah", 100, 200); 

    return 0; 
} 

Выход

func1 blah 10 
func2 blahblah 100 200 
+0

Спасибо! Именно то, что я искал. –

+0

@WhozCraig первые элементы вариационных аргументов ('" func1 "и' "func2" ') отбрасываются, это намеренно? – deamentiaemundi

+0

@deamentiaemundi, они не отбрасываются, и они не являются частью va_list. Они являются формальным параметром аргумента 'fname'' doit' и просто не используются (OP решил сделать это, я просто следовал примеру). Они даже должны быть там? На самом деле, нет. Мы могли бы просто-легко на основе 'va_start' с' f'. – WhozCraig

0

Во-первых: не шути с va_args, если вы понятия не имеете, как аргументы передаются или как работать записи активации.

Лучше всего объявить пустяк() с чрезмерно много аргументов:

недействительный пустяк (недействительный (* p_func)(), INT arg1, внутр арг2, внутр arg3, внутр arg4, внутр Arg5);

и просто позвоните (* p_func)() со всеми этими аргументами. Если вызываемая функция не достигает большего, чем нужно, проблем не будет. Даже если это произойдет, он просто вытащит значения мусора из стека.

+0

Это [ABI] (https://en.wikipedia.org/wiki/Application_binary_interface). На x86-64 он, вероятно, сработает, но нет гарантии для других архитектур. –

Смежные вопросы