WebAssembly学习笔记2-创新互联

WebAssembly学习笔记2
    • JavaScript调用C函数
      • 定义函数导出宏
      • 在JavaScript中调用C导出的函数
    • JavaScript函数注入C环境
      • C函数声明
      • JavaScript实现C函数
      • 优缺点

创新互联专注于企业成都营销网站建设、网站重做改版、敦煌网站定制设计、自适应品牌网站建设、HTML5建站商城网站开发、集团公司官网建设、成都外贸网站制作、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为敦煌等各大城市提供网站开发制作服务。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