EM_ASM宏

用途 返回值 参数访问
EM_JS(return_type, function_name, (args), code) ES_ASM更加青大的替代品,用于执行JS代码 return_type匹配 使用变量名
EM_ASYNC_JS(return_type, function_name, (args), code) 允许在JS实现中使用 async/await,C函数返回一个Promise return_type匹配 使用变量名
EM_ASM(code) 执行嵌入的 JS 代码
EM_ASM_ARGS(code, args...) 执行 JS 代码,可传参 使用 $0, $1
EM_ASM_INT(code, args...) 执行 JS 代码,可传参 int 使用 $0, $1
EM_ASM_DOUBLE(code, args...) 执行 JS 代码,可传参 double 使用 $0, $1
EM_ASM_INT_V(code) 执行 JS 代码 int
EM_ASM_DOUBLE_V(code) 执行 JS 代码 double
EMSCRIPTEN_KEEPALIVE 导出C函数供JS调用

1、EM_JS

这是 EM_ASM 的一个更推荐的替代品,其用于在 C/C++ 中声明一个用JS编写的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <emscripten.h>
#include <iostream>

EM_JS(int, add, (int x, int y), {
return x + y;
});

int main () {
int a = 1;
int b = 2;
int c = add(a, b);
std::cout << "c = " << c << std::endl;
return 0;
}

2、EM_ASYNC_JS

EM_ASYNC_JS 设计的核心目的是让 C/C++ 代码能够调用异步的 JavaScript 代码(如 fetch, setTimeout等)

C/C++函数有返回值(编译使用-s ASYNCIFY

允许C/C++代码直接等待异步操作完成并获取结果。这需要启用Emscripten的Asyncify功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <emscripten.h>
#include <iostream>

EM_ASYNC_JS(int, add, (int x, int y), {
const data = await new Promise((resolve) => {
setTimeout(() => {
resolve(x + y);
}, 2000);
});
return data;
});

int main () {
int a = 1;
int b = 2;
int c = add(a, b);
std::cout << "c = " << c << std::endl;
return 0;
}

3、EM_ASM

最简单的形式,执行嵌入的 JS 代码,详见Emscripten基础

4、EM_ASM_ARGS

通过传参的方式,执行嵌入的JS代码,无返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <emscripten.h>
#include <iostream>

using namespace std;

int main() {
int x = 10;
int y = 20;
EM_ASM_ARGS({
alert(`current data ${$0} ${$1}`);
}, x, y);
cout << x * y << endl;
}

5、EM_ASM_INT

通过传参的方式,执行JS代码并返回一个int类型的值,详见Emscripten基础

6、EM_ASM_DOUBLE

通过传参的方式,执行JS代码并返回一个double类型的值,详见Emscripten基础

7、EM_ASM_INT_V

通过无参的方式,执行JS代码并返回一个int类型的值

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <emscripten.h>
#include <iostream>

using namespace std;

int main() {
int x = EM_ASM_INT_V({
let a = 1;
let b = 2;
return a + b;
});
cout << x << endl;
}

8、EM_ASM_DOUBLE_V

通过无参的方式,执行JS代码并返回一个double类型的值

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <emscripten.h>
#include <iostream>

using namespace std;

int main() {
double x = EM_ASM_DOUBLE_V({
let a = 1.1;
let b = 2.2;
return a + b;
});
cout << x << endl;
}

9、EMSCRIPTEN_KEEPALIVE

Emscripten的EMSCRIPTEN_KEEPALIVE宏用于确保C/C++函数在编译后不会被编译器优化掉,并且可以从JavaScript中调用

这对于在Web环境中使用C/C++代码非常重要

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <emscripten.h>
#include <iostream>

// 使用EMSCRIPTEN_KEEPALIVE宏确保函数可被JavaScript调用
extern "C" {
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
return a + b;
}

EMSCRIPTEN_KEEPALIVE
const char* get_string() {
return "Hello from C++!";
}

EMSCRIPTEN_KEEPALIVE
void print_message() {
std::cout << "Message printed from C++" << std::endl;
}
}

通过编译命令将这些方法导出到test.js中以供JS调用

1
emcc hello-world.cpp -s WASM=1 -s EXPORTED_FUNCTIONS='["_add", "_get_string", "_print_message"]' -o test.js

在HTML中调用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebAssembly Demo</title>
<style>
.button-container { margin: 20px; text-align: center; }
button { padding: 10px 20px; margin: 0 10px; font-size: 16px; cursor: pointer; }
</style>
</head>
<body>
<div class="button-container">
<button class="button" onclick="callAdd()">调用 add(5, 7)</button>
<button class="button" onclick="callGetString()">调用 get_string()</button>
<button class="button" onclick="callPrintMessage()">调用 print_message()</button>
</div>
<script src="./test.js"></script>
<script>
// 等待WebAssembly模块加载完成
Module.onRuntimeInitialized = function() {
console.log('WebAssembly模块已加载');

// 调用add方法
window.callAdd = function() {
const result = Module._add(5, 7);
alert(`5 + 7 = ${result}`);
};

// 调用get_string方法
window.callGetString = function() {
const cStr = Module._get_string();
alert(`C++返回字符串: ${cStr}`);
};

// 调用print_message方法
window.callPrintMessage = function() {
Module._print_message();
alert('已调用print_message,请查看控制台输出');
};
};
</script>
</body>
</html>