Emscripten 从 JavaScript 调用 C/C++
作者:互联网
2026-04-13
因为最后生成的WASM是在前端使用和运行,所以少不了c/c++和js代码之间的接口调用。
Emscripten 提供了三种从 C/C++ 调用 JavaScript 的主要方法:
- 使用
ccall直接调用 - 使用
cwrap包装成JS函数 - 通过
Module对象以下划线_开头的函数名直接调用(这个最方便使用)
1. 编写供 JS 调用的 C++ 代码(基本语法和宏)
#include // 必须包含的头文件
// 使用 extern "C" 避免 C++ 名称修饰
extern "C" {
// 使用 EMSCRIPTEN_KEEPALIVE 宏确保函数不会被优化删除
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
return a + b;
}
} // extern "C"
2. JS 调用 c++ 代码
2.1 ccall
// 使用 ccall(函数名,返回类型,[参数类型,...],[参数值,...])
var result = Module.ccall('add', 'number', ['number', 'number'], [10, 20]);
console.log(result); // 输出 30
2.2 cwrap
// 使用 cwrap(函数名,返回类型,[参数类型,...])
var addFunction = Module.cwrap('add', 'number', ['number', 'number']);
var result = addFunction(10, 20);
console.log(result); // 输出 30
优点:自动化程度高,C函数参数类型为char*时,Emscripten会自动分配和释放临时内存
2.3 通过Module对象以下划线_开头的函数名直接调用
var result = Module._add(10, 20);
console.log(result); // 输出 30
减少调用开销,性能更好,需手动管理内存
3. 如何处理复杂数据类型
3.1 字符串传递:使用Emscripten提供的字符串转换函数
C++ 返回字符串
// C++ 返回字符串
EMSCRIPTEN_KEEPALIVE
const char* get_greeting() {
return "Hello from C++!";
}
// JavaScript 端调用并转换字符串
var ptr = Module._get_greeting();
var str = Module.UTF8ToString(ptr);
console.log(str); // 输出 "Hello from C++!"
JS 传递字符串
#include
#include
EMSCRIPTEN_KEEPALIVE
int get_string_length(const char* str) {
return strlen(str);
}
// 为字符串分配内存,并将字符串复制进去
const str = 'Hello Direct Call';
const buffer = Module._malloc(str.length + 1); // 额外字节存放字符串结束符 ' '
Module.stringToUTF8(str, buffer, str.length + 1); // 将JavaScript字符串转换为UTF8编码存入内存
// 直接调用C函数
const length = Module._get_string_length(buffer);
console.log('String length:', length);
// 务必释放内存!
Module._free(buffer);
-sEXPORTED_RUNTIME_METHODS=['UTF8ToString','stringToUTF8']
内存管理是关键
若手动分配内存(如使用Module._malloc和Module.stringToUTF8),务必在最后使用Module._free释放,防止内存泄漏。若使用ccall/cwrap并指定'string'参数类型,Emscripten会自动管理临时分配的内存。
相关推荐
专题
+ 收藏
+ 收藏
+ 收藏
+ 收藏
+ 收藏
+ 收藏
最新数据
相关文章
现代Qt开发教程(新手篇)1.4——容器
04/16
C++ 类型萃取:重生之我在幼儿园修炼类型学
04/15
C++ 类型擦除:你对象是 Circle 还是 int 不重要,能 draw() 就行,我不挑
04/13
# Vcpkg使用总结2
04/13
UE5.6 Cesium 插件编译踩坑记录(UE 5.6 + MSVC 14.38 + CMake 3.31)
04/13
Emscripten 从 JavaScript 调用 C/C++
04/13
C++学习笔记(38):封装、继承、多态
04/11
C++ 内存管理:分区、自定义分配器、常见问题与检测工具
04/11
从 Unix Mini Shell 到 Browser Playground:我把 fork/exec/pipe 做成了一个可交互 Web 产品
04/08
信奥崔老师:三目运算 (Ternary Operator)
04/07
AI精选
