【问题标题】:How to pass array of strings between javascript and C/C++ code with webassembly/emscripten?如何使用 webassembly/emscripten 在 javascript 和 C/C++ 代码之间传递字符串数组?
【发布时间】:2022-01-14 19:09:20
【问题描述】:

我正在尝试编写一个 Web 应用程序,该应用程序将使用后端 C/C++ 代码进行某种文字处理(例如拼写检查、语法检查、单词分析)。 (我有 c/C++ 代码在另一个桌面应用程序中工作......我想把它带到网络上)。 我想要一个执行此操作的示例最小代码(将字符串数组从 JavaScript 传递到 c/c++ 代码......c/c++ 代码将执行单词操作......我有这个代码...... ..and 生成的字符串数组将被发送回 JavaScript,在那里它们将被进一步处理。(传递 arrays 来回传递很重要) 请指出我可以从哪里开始的任何此类代码/教程。

我搜索了 GitHub。我发现了几个使用 emscripten 的项目,但在任何地方都找不到。 (我能得到一些线索的唯一地方是用 emscripten 构建的 Hunspell ......但是我无法成功构建它)

请告诉我。提前致谢。

【问题讨论】:

    标签: javascript c++ c webassembly emscripten


    【解决方案1】:

    首先准备C++端接收一个字符串(字符数组):

    static char *string_buffer = NULL;
    static size_t string_length = 0;
    
    void EMSCRIPTEN_KEEPALIVE string_start_js(void) {}
    void EMSCRIPTEN_KEEPALIVE string_final_js(void) {}
    
    char * EMSCRIPTEN_KEEPALIVE string_ensure(size_t length) 
    { 
      // ensure that the buffer is long enough
      if (length <= string_length) return string_buffer;
    
      // grow the buffer
      char *new_buffer = realloc(string_buffer, length + 1);
    
      // handle the out of memory
      if (new_buffer == null) return NULL;
    
      // remember
      string_buffer = new_buffer;
      string_length = length;
    
      // done
      return string_buffer;
    }
    
    void EMSCRIPTEN_KEEPALIVE string_handle(size_t length)
    {
      // sanity
      if (string_buffer == NULL || length > string_length) halt;
    
      // terminate
      string_buffer[length] = 0;
    
      // work with the string characters, store/process it 
    }
    
    void EMSCRIPTEN_KEEPALIVE string_clear(void)
    {
      // friendly
      if (string_buffer == NULL) return;
    
      // free
      free(string_buffer);
    
      // remember
      string_buffer = NULL;
      string_length = 0;
    }
    

    从 JavaScript 端向 C++ 端发送一个字符串:

    let strings = ["abc", "defg", "1"];
    
    // inform the C++ side that some strings are going to be transferred
    exports['string_start_js']();
    
    // send all strings
    for (var i = 0; i < strings.length; i++) 
    {
      // single string to transport
      let string = strings[i];
    
      // convert to a byte array
      let string_bytes = new TextEncoder().encode(string);
    
      // ensure enough memory in the C++ side
      let string_offset = exports["string_ensure"](string_bytes.byteLength);
    
      // handle the out of memory 
      if (string_offset == 0) throw "ops...";
    
      // have view of the instance memory
      let view = new Uint8Array(memory.buffer, string_offset, string_bytes.byteLength);
    
      // copy the string bytes to the memory
      view.set(string_bytes);
    
      // handle 
      exports['string_handle'](string_bytes.byteLength);
    }
    
    // inform the C++ side that all strings were transferred 
    exports['string_final_js']();
    
    // clear the used buffer
    exports['string_clear']();
    

    从 C++ 到 WASM 的方式可以更简单:

    • 有一个字符数组(指针)及其长度
    • 调用导入函数以将数组指针提供给 JavaScript 及其长度
    • 制作内存的view
    • view读取字符

    在 C++ 方面是这样的:

    extern "C" {
      extern void string_start_cpp(void);
      extern void string_final_cpp(void);
      extern void string_fetch(char *pointer, size_t length);
    }
    
    void foo(void)
    {
      // inform the JavaScript side that 
      string_start_cpp();
    
      // runtime string
      const char *demo = "abc";
    
      // send to JavaScript
      string_fetch(demo, strlen(demo));
    
      // inform the JavaScript side all strings were send
      string_final_cpp();
    }
    

    在 JavaScript 中,在实例创建期间提供函数:

    string_start_cpp: function(offset, length) 
    {
      console.log("{");
    },
    string_final_cpp: function(offset, length) 
    {
      console.log("}");
    },
    string_fetch: function(offset, length) 
    {
      // view the bytes
      let view = new Uint8Array(memory.buffer, offset, length); 
    
      // convert the UTF-8 bytes to a string
      let string = new TextDecoder().decode(view);
    
      // use
      console.log(string);
    }
    

    我没有测试代码,可能有一些语法错误。您可以在许多地方改进代码,但想法才是最重要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-30
      • 2018-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多