下面是一个使用 emcc
编译的 hello.cpp
,实现 两个字符串相加(拼接) 并在 Web 前端(如 Vue/Vite 或 Electron)中调用的完整示例方案。
✅ 目标
我们用 emcc
把以下 C++ 代码编译成 wasm,并在 JS 中调用 concat("Hello, ", "World!")
,得到 "Hello, World!"
。
🧱 Step 1:C++ 源码(hello.cpp
)
#include <string>
#include <cstring>
#include <cstdlib>
extern "C" {
// 拼接两个字符串,返回新的 malloc 分配的字符串
const char* concat(const char* a, const char* b) {
std::string sa(a);
std::string sb(b);
std::string result = sa + sb;
// 使用 malloc 分配返回值,JS 中需要手动释放(或忽略内存)
char* cstr = (char*)malloc(result.size() + 1);
std::strcpy(cstr, result.c_str());
return cstr;
}
// 提供释放内存函数
void free_str(char* ptr) {
free(ptr);
}
}
🛠️ Step 2:emcc 编译命令
emcc hello.cpp -o hello.js \
-s EXPORTED_FUNCTIONS='["_concat", "_free_str"]' \
-s EXPORTED_RUNTIME_METHODS='["cwrap", "UTF8ToString", "stringToUTF8", "lengthBytesUTF8", "allocateUTF8"]' \
-s MODULARIZE=1 \
-s EXPORT_ES6=1 \
-s ENVIRONMENT='web' \
-s ALLOW_MEMORY_GROWTH=1
生成:
hello.js ← 模块加载器(ES6 模块)
hello.wasm ← WebAssembly 模块
📦 Step 3:在 Vue/Vite 中使用
hello-loader.js
import HelloModule from './hello.js'
export async function loadConcat() {
const module = await HelloModule({
locateFile: (path) => path === 'hello.wasm' ? '/hello.wasm' : path
})
const concat = module.cwrap('concat', 'number', ['string', 'string']);
const free_str = module.cwrap('free_str', null, ['number']);
// 包装函数,返回 JS 字符串并释放内存
const concatStr = (a, b) => {
const ptr = concat(a, b);
const result = module.UTF8ToString(ptr);
free_str(ptr);
return result;
}
return concatStr;
}
App.vue
示例
<template>
<div>
<h2>拼接结果:{{ result }}</h2>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { loadConcat } from './wasm/hello-loader'
const result = ref('')
onMounted(async () => {
const concat = await loadConcat()
result.value = concat("Hello, ", "WebAssembly!")
})
</script>
🧪 输出
拼接结果:Hello, WebAssembly!
✅ 说明与注意事项
项目 | 说明 |
---|---|
UTF8ToString |
把 wasm 返回的char* 指针转为 JS 字符串 |
stringToUTF8 等 |
JS 字符串传入 wasm 也可以用更复杂内存分配 |
free(ptr) |
你可以自己控制是否释放(长生命周期可缓存) |