WebAssembly学习笔记2-创新互联
- JavaScript调用C函数
- 定义函数导出宏
- 在JavaScript中调用C导出的函数
- JavaScript函数注入C环境
- C函数声明
- JavaScript实现C函数
- 优缺点
之前通过Module._main()调用了C/C++入口main()函数,但这只是因为Emscripten会默认导出main函数,普通C函数需要自定义导出方法
定义函数导出宏为了方便函数导出,我们需要先定义一个函数导出宏。该宏需要完成以下功能:
- 使用C风格的符号修饰。
- 避免函数因为缺乏引用而导致在编译链接时被优化器删除。
- 为了保持足够的兼容性,宏需要根据不同的环境——原生代码环境与Emscripten环境、纯C/C++环境等,自动切换合适的行为
为了满足以上三点,定义宏 EM_PORT_API 如下:
#ifndef EM_PORT_API
# if defined(__EMSCRIPTEN__)
# include# if defined(__cplusplus)
# define EM_PORT_API(rettype) extern "C" rettype EMSCRIPTEN_KEEPALIVE
# else
# define EM_PORT_API(rettype) rettype EMSCRIPTEN_KEEPALIVE
# endif
# else
# if defined(__cplusplus)
# define EM_PORT_API(rettype) extern "C" rettype
# else
# define EM_PORT_API(rettype) rettype
# endif
# endif
#endif
EMSCRIPTEN 用于探测是否是Emscripten环境
__cplusplus 用于探测是否是C++环境
EMSCRIPTEN_KEEPALIVE是Emscripten特有的宏,用于告知编译器后续函数在优化时必须保留,并且该函数将被导出至JavaScript环境
在C/C++中使用 EM_PORT_API 宏定义函数声明:
EM_PORT_API(int) func(int param);
在Emscripten中将被展开:
#includeextern "C" int EMSCRIPTEN_KEEPALIVE func(int param);
在JavaScript中调用C导出的函数创建C文件,代码如下:
//此处省略EM_PORT_API宏定义
#includeEM_PORT_API(int) show_me_the_answer() {
return 42;
}
EM_PORT_API(float) add(float a, float b) {
return a+b;
}
使用emcc编译之,并在html引用编译后的js,JavaScript调用C导出的函数代码如下:
需要注意:
JavaScript是弱类型语言,在调用函数时并不要求调用方与被调用方签名一致,这与C/C++有本质的区别。
在JavaScript环境中,如果给出的参数个数不一致,多出来的会被舍弃(从左至右),少的自动以undefined填充。
自然就有:
console.log(Module._add(1)); //输出NaN
JavaScript函数注入C环境
C函数声明创建C文件capi.cc
#includeEM_PORT_API(int) js_add(int i, int j);
EM_PORT_API(void) js_console_log_int(int param);
EM_PORT_API(void) print_the_answer() {
int i = js_add(21, 21);
js_console_log_int(i);
}
EM_PORT_API(int) show_me_the_answer_bi();
EM_PORT_API(void) print_the_answer_bi() {
printf("%d\n",show_me_the_answer_bi());
}
此处js_add和 js_console_log_int show_me_the_answer_bi 只是在C中给出了声明,我们需要在JavaScript中实现
JavaScript实现C函数创建pkg.js,代码如下:
// mergeInto 注入方法不能直接使用闭包
mergeInto(LibraryManager.library,{js_add: function(a, b){console.log("js_add");
return a+b;
},
js_console_log_int: function(param) {console.log("js_console_log_int: "+param);
},
show_me_the_answer_bi: function() {return jsShowMeTheAnswer();
}
});
执行以下命令编译:
emcc capi.cc --js-library pkg.js -o capi.js
–js-library pkg.js表示将pkg.js作为附加库参与链接。
按照之前的例子在网页中将生成的capi.js载入,并调用print_the_answer
由于mergeInto注入方法不能注入闭包,可以通过在注入方法中调用其他方法来间接实现。这种方法既能避免不能直接注入闭包的限制,而且还能动态调整注入函数。
优缺点优点: 保持C代码的纯净——C代码中不必包含JavaScript的成分
缺点: 需要额外创建一个js库,维护较麻烦,并且还要特别注意保持函数声明和实现时定义的统一
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
当前文章:WebAssembly学习笔记2-创新互联
本文地址:http://ybzwz.com/article/ccdsgj.html