C 语言
- 主动调用函数
// - 函数声明
double addFunc(int a, double b){
return a + b;
}
// - 测试函数
void libffi_add(){
// - 构造函数模板 包括参数和返回值
ffi_cif cif;
ffi_type *argTyeps[2] = { &ffi_type_sint, &ffi_type_double };
ffi_type *rettype = &ffi_type_double;
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, rettype, argTyeps);
// - 参数
int a = 100;
double b = 0.5;
void *args[2] = { &a , &b};
double result = 0;
// - 使用cif函数签名信息调用函数
ffi_call(&cif, (void *)&addFunc, &result, args);
}
- 修改函数的实现
// - 修改的函数指针的函数实现
void register_add_func(ffi_cif *cif,void *ret,void **args,void *userdata){
int a = *(int *)args[0];
double b = *(double *)args[1];
*(double *)ret = a + b;
}
void libffi_register_add(){
// - 函数模板
// - 1. 参数
unsigned argsCount = 2;
ffi_type **argTyeps = malloc(sizeof(ffi_type *) * argsCount);
argTyeps[0] = &ffi_type_sint;
argTyeps[1] = &ffi_type_double;
// - 2. 返回值
ffi_type *rettype = malloc(sizeof(void *));
rettype = &ffi_type_double;
// - 3. 构建函数模板
ffi_cif *cif = malloc(sizeof(ffi_cif));
ffi_prep_cif(cif, FFI_DEFAULT_ABI, argsCount, rettype, argTyeps);
// - 绑定 closure 和 add 函数指针
double (*add)(int, double) = NULL;
ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), (void *)&add);
// - 自定义传递的参数(需要保持不释放) 实际使用时, ffi_type、ffi_closure和userdata都需要一直存在
NSString *userdata = @"123";
CFRetain((__bridge CFTypeRef)(userdata));
// - 替换函数调用
/* 执行顺序:
1. ffi_closure_SYSV_V或者ffi_closure_SYSV
2. ffi_closure_SYSV_inner
3. register_add_func
*/
ffi_prep_closure_loc(closure, cif, ®ister_add_func, (__bridge void *)(userdata), add);
// - 测试代码
double result = add(1, 0.5);
assert(result == 1.5);
}
OC方法
- 主动调用方法
@interface Sark : NSObject @end
@implementation Sark
- (int)fooWithBar:(int)bar baz:(int)baz {
return bar + baz;
}
@end
void testFFICall() {
// - 构建函数模板
ffi_cif cif;
ffi_type *argumentTypes[] = {&ffi_type_pointer, &ffi_type_pointer, &ffi_type_sint32, &ffi_type_sint32};
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &ffi_type_pointer, argumentTypes);
// - 传递的参数和返回值
Sark *sark = [Sark new];
SEL selector = @selector(fooWithBar:baz:);
int bar = 123;
int baz = 456;
void *arguments[] = {&sark, &selector, &bar, &baz};
int retValue;
// - 方法调用, 在
IMP imp = [sark methodForSelector:selector];
ffi_call(&cif, imp, &retValue, arguments);
NSLog(@"ffi_call: %d", retValue);
}
- 修改方法实现
@interface Sark : NSObject @end
@implementation Sark
- (int)fooWithBar:(int)bar baz:(int)baz {
return bar + baz;
}
@end
// - 修改方法提的实现
void closureCalled(ffi_cif *cif, void *ret, void **args, void *userdata) {
int bar = *((int *)args[2]);
int baz = *((int *)args[3]);
*((int *)ret) = bar * baz;
}
void testFFIClosure() {
// - 构建函数模板,
ffi_cif cif;
ffi_type *argumentTypes[] = {&ffi_type_pointer, &ffi_type_pointer, &ffi_type_sint32, &ffi_type_sint32};
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &ffi_type_pointer, argumentTypes);
// - 关联 IMP 和 ffi_closure
IMP newIMP;
ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), (void *)&newIMP);
// 关联 closure 和 cif 和 closureCalled
ffi_prep_closure_loc(closure, &cif, closureCalled, NULL, NULL);
// - 使用 runtime 接口动态地将 fooWithBar:baz 方法绑定到 closureCalled 函数指针上
Method method = class_getInstanceMethod([Sark class], @selector(fooWithBar:baz:));
method_setImplementation(method, newIMP);
// - 测试代码
// - 构建函数模板时候, 不必传入值, 但是传入了参数个数和参数大小, 这样在栈中取值得时候, 可以取到值
// - 在调用fooWithBar:baz:方法时 参数应该是压入栈中或者存在寄存器中, 在closureCalled中使用这些参数时候, 应该是直接去栈中/寄存器中取的.
Sark *sark = [Sark new];
int ret = [sark fooWithBar:123 baz:456];
NSLog(@"ffi_closure: %d", ret);
}