WebAssembly.Instance 实例化后为什么无法访问导出的函数?

南宫书圻 阅读 5

我用 Emscripten 编译了一个简单的 C 函数,想在浏览器里调用。加载 .wasm 文件后,通过 WebAssembly.instantiate() 创建了 Instance,但打印 instance.exports 时发现里面是空的,明明 C 代码里用了 EMSCRIPTEN_KEEPALIVE 标记了函数。

我试过检查模块是否加载成功,也确认了编译命令加了 -s EXPORTED_FUNCTIONS,但还是拿不到导出的函数。是不是实例化方式有问题?我的 JS 代码大概是这样:

fetch('test.wasm')
  .then(res => res.arrayBuffer())
  .then(bytes => WebAssembly.instantiate(bytes))
  .then(result => {
    console.log(result.instance.exports); // 输出 {}
  });
我来解答 赞 0 收藏
二维码
手机扫码查看
1 条解答
志选的笔记
这个问题很典型,十有八九是导出函数的命名问题。

Emscripten 编译出来的 wasm,导出的函数名会带个下划线前缀。你在 C 里写的 int add(int a, int b),在 JS 里导出后叫 _add,不是 add

所以你先试试这样访问:

console.log(result.instance.exports._add); // 看看能不能拿到函数
result.instance.exports._add(1, 2); // 调用试试


如果还是 undefined,那问题在编译参数这块。

你的编译命令大概长这样对吧:

emcc test.c -o test.js -s EXPORTED_FUNCTIONS='["_main", "_add"]' -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'


注意几个点:

1. 导出函数名单独用引号包住不行,得用单引号包双引号这种嵌套写法,或者用逗号分隔
2. _main 必须加上去,不然 Emscripten 生成的入口点没导出来,整个模块可能不正常
3. 如果你想导出所有函数,可以加 -s EXPORT_ALL=1

还有一种情况是,你用的是新版 Emscripten(2.0+),它的默认行为有变化。如果上面的方法不行,试试在编译时加上:

emcc test.c -o test.js -s EXPORTED_FUNCTIONS='["_main", "_add"]' -s EXPORT_ALL=1 --no-entry


--no-entry 是告诉编译器没有 main 函数,适合只导出单独函数的情况。

你先把编译命令贴出来,我看看具体是哪儿的问题。
点赞
2026-03-18 23:07