在JavaScript中调用C导出函数——1

  • 编写程序c_call_js.c

     为了方便函数导出,我们需要先定义一个函数导出宏,该宏需要完成以下功能:

  1. 使用C风格符号修饰。我们知道,由于引入了多态、重载、模板等特性,C语言环境下的符号修饰策略(既函数、变量在最终编译成果中的名字的生成规则)非常复杂,并且不同的C编译器有着各自的符号修饰策略,如果不做额外处理,我们在C中创建函数的时候,很难预知它在最终编译成果中的名字——这与C语言环境完全不同。因此当我们试图将main()函数之外的全局函数导出至JavaScript时,必须强制使用C风格的符号修饰,以保持函数名称在C/C环境以及JavaScript环境中有统一的对应规则。
  2. 避免函数因为缺乏引用而导致在编译时被优化器删除。如果某个导出函数仅供JavaScript调用,而在C/C++环境中从未被使用,开启某些优化选项(比如-O2以上)时,函数有可能被编译器优化删除,因此需要提前告知编译器:该函数必须保留,不能删除,不能改名。
  3. 为了保持足够的兼容性,宏需要根据不同的环境——原生NativeCode环境与Emscripten环境、纯C环境与C++环境等——自动切换合适的行为。
#ifndef EM_PORT_API//定义EM_PORT_API宏
#	if defined(__EMSCRIPTEN__)//探测是否是EmScripten环境
#		include <emscripten.h>
#		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)//探测是否是C++环境
#			define EM_PORT_API(rettype) extern "C" rettype
#		else
#			define EM_PORT_API(rettype) rettype
#		endif
#	endif
#endif

#include <stdio.h>

EM_PORT_API(int) show_me_the_answer() 
{
	return 42;
}

EM_PORT_API(float) add(float a, float b)
{
	return a + b;
}
  • 通过命令emcc c_call_js.c -o c_call_js.jsc程序编译为wasm
  • 创建页面c_call_js.html,并在页面中添加调用c程序代码
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Emscripten:Export1</title>
  </head>
  <body>
    <script>
    Module = {};
    Module.onRuntimeInitialized = function() {
      console.log(Module._show_me_the_answer());
      console.log(Module._add(12, 1.0));
    }
    </script>
    <script src="c_call_js.js"></script>
  </body>
</html>
  • 通过命令emrun --no_browser --port 8080 文件路径\c_call_js.html,在开发者页面的控制台查看函数调用结果
发布了315 篇原创文章 · 获赞 119 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/w144215160044/article/details/100156754