Подтвердить что ты не робот

Указатели функций в Objective C

Быстрый вопрос. Кто-нибудь знает, как получить указатель функции объектного метода c? Я могу объявить С++-метод как указатель функции, но это метод обратного вызова, так что метод С++ должен быть частью класса , ТАК, ЧТО ЭТО МОЖЕТ ДОСТУПИТЬ ИНСТРУМЕНТАЛЬНЫЕ ПОЛЯ. Я не знаю, как сделать часть метода С++ объектного класса c. Любые предложения?

4b9b3361

Ответ 1

Как правило, вам нужно две части информации, чтобы перезвонить в Objective-C; метод, который нужно вызвать, и объект для его вызова. Ни один из селекторов или только IMP - результат instanceMethodForSelector: - будет достаточно информации.

Большинство API обратного вызова предоставляют указатель контекста, который рассматривается как непрозрачное значение, которое передается обратному вызову. Это ключ к вашей загадке.

т.е. если у вас есть функция обратного вызова, которая объявляется как:

typedef void (*CallBackFuncType)(int something, char *else, void *context);

И некоторый API, который потребляет указатель указанного типа функции обратного вызова:

void APIThatWillCallBack(int f1, int f2, CallBackFuncType callback, void *context);

Затем вы выполнили бы свой обратный вызов примерно так:

void MyCallbackDude(int a, char *b, void *context) {
    [((MyCallbackObjectClass*)context) myMethodThatTakesSomething: a else: b];
}

И тогда вы бы назвали API похожим на это:

MyCallbackObjectClass *callbackContext = [MyCallbackObjectClass new];
APIThatWillCallBack(17, 42, MyCallbackDude, (void*)callbackContext);

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

Ответ 2

Вы можете сделать это с помощью @selector и SEL:

SEL sel = @selector(myMethod:);

/* Equivalent to [someObject myMethod:Paramater] */
[someObject performSelector:sel withObject:Parameter]

Существует также тип IMP...

IMP imp = [someObject methodForSelector:sel];

/* don't remember if this syntax is correct; it been a while...
 * the idea is that it like a function pointer. */
imp(someObject, sel, Parameter); 

Обновление на основе ваших комментариев

Если вы не хотите указывать объект, в этом случае вы просите что-то ужасно не переносное. По сути, вам нужны лямбда-выражения, которые не являются признаком C, хотя он приходит в С++ 0x.

Итак, мое решение будет "там", отрывочным и не переносимым...

НО... возможно, вы можете сделать это с генерацией кода времени выполнения...

Вы можете начать с написания функции заглушки в сборке (если вы хотите x86)

push dword 0 ; SEL will go here
push dword 0 ; Object will go here
push dword 0 ; IMP will go here
pop eax      ; eax = imp
call eax     ; call imp
add esp, 8   ; cleanup stack
ret          ; return

Эта команда собрана для:

0068 0000 6800 0000 0000 0068 0000 5800 d0ff c481 0004 0000 00c3

Обратите внимание, что инструкция push dword 0 - это байты 68 00 00 00 00. Мы будем заполнять нули указателем во время выполнения.

Итак, мы можем скопировать это в буфер malloc() 'd, исправить его и вызвать mprotect(), чтобы сделать его исполняемым.

Ниже приведен код для иллюстративных целей, и я понятия не имею, работает ли он.: -)

/* x86 code... */
char code[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0x68,
                0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
                0x00, 0x00, 0x00, 0x58, 0xff, 0xd0,
                0x81, 0xc4, 0x04, 0x00, 0x00, 0x00,
                0xc3 };

char *buf = malloc(sizeof(code));

SEL Selector = @selector(Method);
IMP Imp = [object methodForSelector:Selector];

/* Copy template */
memcpy(buf, code, sizeof(code));

/* Patch the "push dword 0" parts with your arguments
 * This assumes everything is 32-bit, including SEL, IMP, etc. */
memcpy(buf + 1, &Selector, sizeof(Selector));
memcpy(buf + 6, &object, sizeof(object));
memcpy(buf + 11, &Imp, sizeof(Imp));

/* Now here comes the sketchy part...
 * Make it executable and turn it into a function pointer.  */
mprotect(buf, sizeof(code), PROT_EXEC);
void (*Function)() = (void(*)())buf;

/* Now, crazy as it sounds, you should be able to do: */
Function();

Возможно, вы захотите сделать [object retain] до тех пор, пока эта функция существует, и [object release], когда и если вы должны ее освободить. (Вероятно, лучше всего обернуть эту sketcyness внутри объекта в любом случае, а затем использовать обычный objc refcounting для управления буфером и ссылкой на object.) Возможно, вы также захотите использовать mmap() для размещения вместо malloc()..

Если это звучит излишне сложно, потому что это так.: -)

Ответ 3

Вы можете создать класс С++ в качестве обертки. И вызовите сообщение цели C из этого класса. Не забудьте сделать свой файл yoursource.mm вместо yoursource.cpp.