Как передать простые анонимные функции как параметры в C - PullRequest
5 голосов
/ 10 августа 2011

Я уверен, что некоторые варианты этого вопроса уже задавались ранее, но все другие, подобные вопросы по SO кажутся гораздо более сложными, включая передачу массивов и других форм данных.Мой сценарий намного проще, поэтому я надеюсь, что есть простое / элегантное решение.

Есть ли способ, которым я могу создать анонимную функцию или передать строку кода в качестве указателя на функцию в другую функцию?

В моем случае у меня есть ряд различных операций.До и после каждой строки кода есть задачи, которые я хочу выполнить, которые никогда не меняются.Вместо дублирования начального и конечного кода, я хотел бы написать функцию, которая принимает указатель функции в качестве параметра и выполняет весь код в необходимом порядке.

Моя проблема в том, что это не стоитопределяя 30 функций для каждой операции, поскольку они представляют собой одну строку кода.Если я не могу создать анонимную функцию, могу ли я упростить свой код на C?

Если мой запрос не совсем понятен.Вот немного псевдокода для пояснения.Мой код намного более значим, чем этот, но приведенный ниже код дает точную оценку.

void Tests()
{
  //Step #1
  printf("This is the beginning, always constant.");
  something_unique = a_var * 42;  //This is the line I'd like to pass as an anon-function.
  printf("End code, never changes");
  a_var++;

  //Step #2
  printf("This is the beginning, always constant.");
  a_diff_var = "arbitrary";  //This is the line I'd like to pass as an anon-function.
  printf("End code, never changes");
  a_var++;

  ...
  ...

  //Step #30
  printf("This is the beginning, always constant.");
  var_30 = "Yup, still executing the same code around a different operation.  Would be nice to refactor...";  //This is the line I'd like to pass as an anon-function.
  printf("End code, never changes");
  a_var++;
}

Ответы [ 6 ]

9 голосов
/ 10 августа 2011

Не в традиционном смысле анонимных функций, но вы можете макрос его:

#define do_something(blah) {\
    printf("This is the beginning, always constant.");\
    blah;\
    printf("End code, never changes");\
    a_var++;\
}

Тогда он становится

do_something(something_unique = a_var * 42)
4 голосов
/ 10 августа 2011

Нет, вы не можете. Анонимные функции доступны только на функциональных языках (и языках с функциональными подмножествами), и, как мы все знаем, c дисфункциональна; ^)

2 голосов
/ 10 августа 2011

Лучший способ упростить ваш код, возможно, заключить цикл for в оператор switch.

int a_var;
for ( a_var = 0; a_var <= 30; a_var++ )
{
    starteroperations();
    switch (a_var)
    {
         case 0:
             operation0(); break;
         case ...:
             operationx(); break;
         case 30:
             ...
    }
    closingoperations();
 }
2 голосов
/ 10 августа 2011

В C и до 0x C ++, нет.

В C ++ 0x, да, с использованием лямбда-функций .

0 голосов
/ 10 августа 2011

Либо вы идете по пути case, предложенному @dcpomero, либо делаете следующее:

typedef void job(int);
job test1; void test1(int a_var) { something_unique = a_var * 42; }
job test2; void test2(int a_var) { a_diff_var = "arbitrary"; }
job test3; void test3(int a_var) { var_30 = "Yup, still executing the same code around a different operation.  Would be nice to refactor..."; }

job * tests[] = { test1, test2, test3, testn };

void Tests()
{
    int i;
    for (i=0; i < sizeof tests/sizeof tests[0]; i++) {
        printf("This is the beginning, always constant.");
        tests[i](a_var);
        printf("End code, never changes");
        a_var++;
    }
}
0 голосов
/ 10 августа 2011

Если вы можете использовать Clang, вы можете использовать преимущества блоков. Для изучения блоков вы можете использовать документацию Apple , спецификацию языка блоков Clang и замечания по реализации и предложение Apple для рабочей группы ISO C добавить блоки на стандартный язык C, а также тонну постов в блоге.

Используя блоки, вы можете написать:

/* Block variables are declared like function pointers
 * but use ^ ("block pointer") instead of * ("normal pointer"). */
void (^before)(void) = void ^(void) { puts("before"); };

/* Blocks infer the return type, so you don't need to declare it
 * in the block definition. */
void (^after)(void) = ^(void) { puts("after"); };

/* The default arguments are assumed to be void, so you could even
 * just define after as
 *
 *     ^{ puts("after"); };
 */

before();
foo = bar + baz*kablooie;
after();

В этом примере имена анонимных блоков присваиваются путем присвоения переменной блока. Вы также можете определить и вызвать блок напрямую:

   ^{ puts("!"); } ();
/*|  definition   | invocation of anonymous function |*/

Это также делает определение "struct-objects" (ООП в C с использованием структур) очень простым.

И Clang, и GCC поддерживают внутренние / вложенные функции как расширение стандарта C. Это позволит вам определить функцию непосредственно перед получением ее адреса, что может быть альтернативой, если ваша структура потока управления позволяет ей : указатели на внутренние функции не могут выходить из их непосредственной области видимости. Как говорят в документах:

Если вы попытаетесь вызвать вложенную функцию через ее адрес после выхода из содержащей функции, весь ад вырвется на свободу. Если вы попытаетесь вызвать его после выхода из уровня, содержащего область, и если он ссылается на некоторые переменные, которые больше не находятся в области, вам может повезти, но не стоит рисковать. Однако, если вложенная функция не относится ни к чему, что вышло из области видимости, вы должны быть в безопасности.

Используя вложенные функции, вы можете написать:

 /* Nested functions are defined just like normal functions.
  * The difference is that they are not defined at "file scope"
  * but instead are defined inside another function. */
 void before(void) { puts("before"); };
 void after(void) { puts("after"); };

 before();
 foo = bar + baz*kablooie;
 after();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...