Вы можете сделать это в Clang, используя расширение языка «Blocks».Как отмечалось, были попытки стандартизировать этот (и он не был получен с враждебностью или чем-то еще), но они движутся медленно.
В переводе на использование блоков ваш пример может выглядетькак это:
#include <stdlib.h>
#include <Block.h>
typedef void (^GetPw)(int); // notice how Block pointer types are used
typedef void (*GetPw_Impl)(char*, int); // the same way as function pointer types
typedef struct
{
GetPw get;
char string[10];
} password;
extern void hiddenStringInput(char*, int);
extern void setPw(char dst [static 10], char * src);
GetPw bindPw (GetPw_Impl get_impl, char * pw)
{
return Block_copy (^ (int key) {
get_impl (pw, key);
});
}
int main()
{
password userPassword;
setPw(userPassword.string, "secret");
userPassword.get = bindPw(hiddenStringInput, userPassword.string);
userPassword.get(10);
return EXIT_SUCCESS;
}
Существуют некоторые тонкости в способе захвата массивов, которые могут запутать этот случай;в примере захватывается пароль с помощью обычного указателя и предполагается, что userPassword
отвечает за владение им отдельно от блока.
Поскольку блок захватывает значения, ему необходимо предоставить и освободить динамическое хранилище для копийзахваченные значения, которые будут созданы при копировании самого блока из области, в которой он был создан;это делается с помощью функций Block_copy
и Block_release
.
Типы блоков (синтаксически функциональные указатели, но с использованием ^
вместо *
) являются просто указателями - нетспособ доступа к базовому объекту блока, точно так же как и к основным функциям C.
Это Clang API - стандартизация изменит это немного, и, вероятно, уменьшит потребность в динамическом распределении памяти для копирования блока вокруг(но Clang API отражает, как они в настоящее время наиболее часто используются).