IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> iOS libffi 一些理解 -> 正文阅读

[移动开发]iOS libffi 一些理解

C 语言

  1. 主动调用函数
// - 函数声明
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);
}
  1. 修改函数的实现
// - 修改的函数指针的函数实现
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, &register_add_func, (__bridge void *)(userdata), add);

	// - 测试代码
    double result = add(1, 0.5);
    assert(result == 1.5);
}

OC方法

  1. 主动调用方法
@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);
}
  1. 修改方法实现
@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);
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-18 16:06:39  更:2021-12-18 16:07:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:05:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码