'WebAssembly return string use C

How can I return a JavaScript string from a WebAssembly function?

https://dev.to/azure/passing-strings-from-c-to-javascript-in-web-assembly-1p01 - not working

C

#include <stdio.h>
#include <string.h>

void jsPrintString(const char *s, uint16_t len);

void print() {
  const char* str = "Hello from C++!";
  jsPrintString(str, strlen(str));
}

Compiler:

emcc -Os start.c  -s STANDALONE_WASM -s EXPORTED_FUNCTIONS="['_hello']" -s ERROR_ON_UNDEFINED_SYMBOLS=0 -Wl,--no-entry -o "test.wasm"

Javascript:

const memory = new WebAssembly.Memory({ initial: 1 });

    function handlePrintString (offset, length) {
      console.log(offset, length);
      const bytes = new Uint8Array(memory.buffer, offset, length);
      const string = new TextDecoder('utf8').decode(bytes);
      console.log(string); //empty ???????????????????????????????????
    }

    const importObject = {
      env: {
        jsPrintString: handlePrintString,
        memory: memory
      },

      js: { mem: memory }
    };

    WebAssembly.instantiateStreaming(fetch('/js/test.wasm'), importObject)
      .then(obj => {
        console.log(obj.instance.exports);
        console.log(obj.instance.exports.print());
      });

memory ArrayBuffer [0,0,0,0,0,0,0,0,0,0,0.....] ???



Solution 1:[1]

How can I return a JavaScript string from a WebAssembly function?

You cannot. You have to copy it to memory shared with JavaScript.

void hello(char *array) {
    const my_string = "Hello from C++!";
    memcpy(array, my_string, strlen(my_string));
}
  (async () => {
    const response = await fetch('/js/test.wasm');
    const bytes = await response.arrayBuffer();
    const results = await WebAssembly.instantiate(bytes, {});
    const { instance: { exports: { memory, hello } }} = results;
    const array = new Uint8Array(memory.buffer, 0, 15);
    hello(array.byteOffset);
    console.log(new TextDecoder('utf8').decode(array)); // Hello from C++!
  })();

Solution 2:[2]

You're nearly there with your code, it is possible to do it as you imply. You don't have to explicitly copy to shared memory as the top comment describes. It's explained in more detail on this blog post here.

C code:

const char* getString() {
  return "Hello World!";
}

Compile it with

clang --target=wasm32 -nostdlib -Wl,--no-entry -Wl,--export-all -o main.wasm main.c

And JS code:

var importObject = { imports: { imported_func: arg => console.log(arg) } };

WebAssembly.instantiateStreaming(fetch('main.wasm'), importObject)
.then(obj => {

  var charArray = new Int8Array(
    obj.instance.exports.memory.buffer, // WASM's memory
    obj.instance.exports.getString(), // char's pointer
    12                                 // The string's length
  );

  // Convert from ASCII code to char
  let string = String.fromCharCode.apply(null, charArray) 
  console.log(string);
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 GirkovArpa
Solution 2 Iron Toad Tough