Как уже сказано в заголовке, я пытаюсь объявить вложенную функцию и вернуть указатель на эту функцию. Я хочу, чтобы эта функция «не» возвращала новый указатель на функцию, который вернет отрицание того, чем была исходная функция.
Вот что у меня есть:
someType not( someType original ) {
int isNot( ListEntry* entry ) {
return !original( entry );
}
someType resultFunc = calloc( 1024, 1 );
memcpy( resultFunc, &isNot, 1024 );
return resultFunc;
}
someType определяется как:
typedef int(*someType)(ListEntry* entry)
Я использую GCC.
Вы можете включить вложенные функции с помощью флага:
-fnested-functions
при компиляции.
Я также никогда не слышал о вложенных функциях в C, но если gcc поддерживает это, это не будет работать так, как вы ожидаете. Вы просто копируете машинные инструкции isNot, и они не будут включать фактическое значение «original» во время вызова «not».
Вы должны использовать класс C++ для реализации функциональный объект, в котором хранится указатель, который вы можете инициализировать значением «оригинал» и возвращать экземпляр этого класса из «не».
Стив, у вас совершенно неверная ментальная модель того, что такое функция C.
someType resultFunc = calloc( 1024, 1 );
memcpy( resultFunc, &isNot, 1024 );
Из фрагмента вашего кода я могу предположить, что вы думаете, что можете скопировать скомпилированный код функции в блок памяти, а затем повторно использовать его. Подобные вещи пахнут Лиспом, за исключением того, что даже в шепелявке вы этого не делаете.
Фактически, когда вы говорите «& isNot», вы получаете указатель на функцию. Копирование памяти, на которую указывает указатель, контрпродуктивно - память была инициализирована при загрузке исполняемого файла в память и не меняется. В любом случае, запись someFunc () вызовет дамп ядра, так как память кучи, связанная с someFunc, не может быть выполнена - это защищает вас от всех видов вирусов.
Кажется, вы ожидаете реализации замыканий на C. Этой реализации просто нет. В отличие от Lisp, Perl или Ruby, C не может сохранять элементы фрейма стека после выхода из этого фрейма. Даже если в некоторых компиляторах разрешены вложенные функции, я уверен, что вы не можете ссылаться на неглобальные переменные изнутри этих функций. Закрытие для замыканий - это действительно объект C++, который хранит состояние и реализует operator (), но это совершенно другой подход, и вам все равно придется делать что-то вручную.
Обновление: здесь - соответствующая часть документации GCC. Ищите «Но этот метод работает только до тех пор, пока содержащая функция (взломать, в этом примере) не завершает работу».
Вы не сможете делать это так, как хотите. У вас есть несколько альтернативных вариантов.
Вы можете использовать макросы:
#define FN_NOT(F) !F
#define notSomeFunc FN_NOT(someFunc)
...
x = notSomeFunc(entry);
Но я подозреваю, что вы хотели передать отрицательную функцию другим функциям, которые принимают указатели на функции, так что это не сработает.
Вы можете изменить свои интерфейсы, чтобы принимать дополнительную информацию, например
struct closure {
void *env;
int (*f)(struct closure* extra, ListEntry*);
};
static int isNot(struct closure* extra, ListEntry *entry) {
someType original = extra->env;
return !original(entry);
}
struct closure not(someType original) {
closure rv;
rv.env = original;
rv.f = &isNot;
return rv;
}
А затем используйте это как:
struct closure inverse_fn;
inverse_fn = not( &fn );
if ( inverse_fn.f(&inverse_fn, entry) ) {
...
}
Есть и другие вещи, которые вы можете попробовать, например функции JITing во время выполнения, но такие методы будут зависеть от платформы и архитектуры. Это неудобное решение, но чистый C и переносимый.
спасибо за ссылку, моя любимая цитата была: «Если вы попытаетесь вызвать вложенную функцию через ее адрес после того, как содержащая функция завершится, все вырвется наружу».