Other answers have not addressed how to return strings from C++. Here is a way to pass a string from c++ to javascript by passing a string by reference.
The emscripten documentation states the following about the types that can be passed to C/C++ functions using cwrap
/ccall
(emscripten docs):
The types are "number" (for a JavaScript number corresponding to a C integer, float, or general pointer), "string" (for a JavaScript string that corresponds to a C char* that represents a string) or "array" (for a JavaScript array or typed array that corresponds to a C array; for typed arrays, it must be a Uint8Array or Int8Array).
As the other answers have pointed out, you need to write the C function using a C string as the argument because that is the emscripten API (not because of extern "C"
).
If you want to return a string, you may think that you can just pass a C string (effectively by reference because it is pointer) and modify that string:
// C function
extern "C" {
void stringTest(char* output) {
output[0] = 'H';
output[1] = 'i';
}
}
// Call to C function in javascript that does not modify output
let stringTestFunction = Module.cwrap('stringTest', null, ['string']);
let output = "12"; // Allocate enough memory
stringTestFunction(output);
console.log(output); // 12
However, this does not work because a copy is created when passed to the function. So, you need to explicitly allocate the memory and pass a pointer instead. Emscripten provides the allocateUTF8
and UTF8ToString
functions for this purpose:
let stringTestFunction = Module.cwrap('stringTest', null, ['number']); // the argument is 'number' because we will pass a pointer
let output = "12";
let ptr = Module.allocateUTF8(output); // allocate memory available to the emscripten runtime and create a pointer
stringTestFunction(ptr);
output = Module.UTF8ToString(ptr); // read from the allocated memory to the javascript string
Module._free(ptr); // release the allocated memory
console.log(output); // Hi
Because we are transforming the string to a character pointer, we could have also called the function directly without using cwrap
(emscripten docs): Module._stringTest(ptr)
. It requires some additional steps but now you have passed a string from C to javascript.
For this example to work, you may need to compile using the following flags: -sEXPORTED_FUNCTIONS="['_stringTest','_malloc','_free']"
and -sEXPORTED_RUNTIME_METHODS="['cwrap','allocateUTF8','UTF8ToString']"
.
There are more general ways to allocate memory for arrays of other types (https://mcmap.net/q/368744/-how-to-handle-passing-returning-array-pointers-to-emscripten-compiled-code).
UTF8ToString
. – Eliathas