日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

调用c++_WebAssembly: 在C代码中调用JS的函数

發布時間:2025/3/19 c/c++ 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 调用c++_WebAssembly: 在C代码中调用JS的函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

0. 前提知識點

  • 導出C中的函數給JS調用:主要是EMSCRIPTEN_KEEPALIVE這個Emscripten環境特有的宏。
  • #include <stdio.h>#ifndef EM_PORT_API # if defined(__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) # define EM_PORT_API(rettype) extern "C" rettype # else # define EM_PORT_API(rettype) rettype # endif # endif #endifEM_PORT_API (int) sum(int *ptr, int count) {int total = 0;for(int i = 0; i < count; i++) {total += ptr[i];}return total; } // js Module._sum(ptr, 10);
  • 使用Emscripten編譯C代碼到wasm。Emscripten的環境比較難配置,主要是網絡問題,但好在有docker環境可以直接使用trzeci/emscripten。推薦寫個build.sh文件方便修改編譯腳本
  • # build.sh docker run --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) trzeci/emscripten emcc helloworld.c -o helloworld.js
  • 使用編譯后的wasm。編譯成功后有會.wasm文件和其對應的.js膠水文件,其目錄:
  • . ├── build.sh ├── index.html ├── test.cc ├── test.js └── test.wasm

    在index.html寫測試代碼

    <script>var Module = {};Module.onRuntimeInitialized = () => {// 在這個回調中調用wasm中的方法}; </script> <!-- 膠水層代碼要放在后臺 --> <script src="test.js"></script>
  • WASM Table: 存儲函數
  • 這是一個包裝了WebAssemble Table 的Javascript包裝對象,具有類數組結構,存儲了多個函數引用。在Javascript或者WebAssemble中創建Table 對象可以同時被Javascript或WebAssemble 訪問和更改。

    1. 在C中調用JS函數之addFunction

    Emscripten提供了多種在C環境調用JavaScript的方法,包括:

  • EM_JS/EM_ASM宏內聯JavaScript代碼
  • emscripten_run_script函數
  • JavaScript函數注入(更準確的描述為:“Implement C API in JavaScript”,既在JavaScript中實現C函數API)
  • 使用addFunction將函數指針傳到C代碼中調用
  • 前3種方法點擊鏈接就可以查看詳細的使用說明

    下面著重描述下第4種方法,主要結合Calling JavaScript functions as function pointers from C實踐一下

    You can use addFunction to return an integer value that represents a function pointer. Passing that integer to C code then lets it call that value as a function pointer, and the JavaScript function you sent to addFunction will be called.
    你可以使用addFunction這個函數的返回值(數字)來代表這個函數的指針。然后將該指針(數字)傳遞給C代碼,然后讓其將該值作為函數指針進行調用,發送給addFunction的JavaScript函數將被調用。

    由上面的說明可以推測出Module有一個addFunction的方法,返回值是一個數字類型。

    在嘗試調用的時候,發現提示說要在編譯的時候導出這個函數

    docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emcc test.cc -o test.js # 要在這里加上-s EXTRA_EXPORTED_RUNTIME_METHODS="['addFunction']"

    再次調用時又發現要設置wasm table成為可以grow的

    此時要在編譯腳本中再加上一行

    -s ALLOW_TABLE_GROWTHYou should build with -s ALLOW_TABLE_GROWTH to allow new functions to be added to the table. Otherwise by default the table has a fixed size.

    加上編譯后,再次運行,發現叕報錯了,缺少函數簽名

    查看文檔

    When using addFunction on LLVM wasm backend, you need to provide an additional second argument, a Wasm function signature string. Each character within a signature string represents a type. The first character represents the return type of a function, and remaining characters are for parameter types. - 'v': void type - 'i': 32-bit integer type - 'j': 64-bit integer type (currently does not exist in JavaScript) - 'f': 32-bit float type - 'd': 64-bit float type

    原來是addFunction的第二個參數需要標明函數的返回值類型,及參數類型,再次修改

    終于成功了,此時已得到了函數的指針,將其傳入到C代碼中就可以調用了。

    下面看下C代碼的實現:

    // 聲明函數簽名,在JS中調用addFunction時,第二個函數的簽名要與此聲明保持一致 typedef void testExternalJSMethod(int p);// 導出一個接收函數 EM_PORT_API (void) pass_fn_ptr(int ptr) {((testExternalJSMethod*)ptr)(1); } // js Module.onRuntimeInitialized = () => {function jsFunction(i) {console.log('定義在js中的function');console.log('從c中傳來的參數: ', i);}// 這里說明下,C語言是先聲明函數返回的類型,所以這里要先寫返回值的類型,再寫其他參數的類型var fPtr = Module.addFunction(jsFunction, 'vi');Module._pass_fn_ptr(fPtr); };

    最后看下輸出結果:

    2. addFunction的優點

  • 相對于第3種方式來說比較靈活,第3種在js中函數的實現的參與到編譯的過程中,而真實應用時給c調用的函數往往混合在業務代碼中,或者是用ts去實現的,這樣第3種方式就會很麻煩;
  • EM_ASM emscripten_run_script這種方式直接將js代碼內聯到C中,沒有什么維護性;
  • #include <emscripten.h>int main() {EM_ASM(console.log('你好,Emscripten!'));return 0; }

    X. 參考文檔

  • C/C++面向WebAssembly編程
  • Calling JavaScript functions as function pointers from C
  • 總結

    以上是生活随笔為你收集整理的调用c++_WebAssembly: 在C代码中调用JS的函数的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。