如何通过emscripten在C++和JavaScript之间传递字符串

iyfamqjs  于 2023-07-01  发布在  Java
关注(0)|答案(4)|浏览(316)

我正在学习emscripten,当在C和JS之间传递字符串时,我甚至不能让最基本的字符串操作工作。
例如,我想写一个字符串长度函数。在C
中:

extern "C" int stringLen(std::string p)
{
    return p.length();
}

从JavaScript调用为:

var len = _stringLen("hi.");

这为我生成了0。我如何使它按预期工作?这里应该使用哪种字符串类型?char const*std::wstringstd::string?似乎都不能用;我总是得到相当随机的值。
这仅仅是个开始...那么我如何从C++* 返回 * 一个字符串呢?

extern "C" char *stringTest()
{
    return "...";
}

在JS中:

var str = _stringTest();

再一次,我找不到一种方法来使这个工作;我总是在JS中得到垃圾。
所以我的问题很明显:如何通过Emscripten在JS和C++之间封送字符串类型?

7rtdyuoh

7rtdyuoh1#

如果你在函数中使用extern“C”,你不能在它的签名中使用C++类型。
因此,如果你想使用std::string,那么你可以使用“Embind”或“WebIDL Binder”。参考这里
我更喜欢embind,所以这是解决您的问题的示例代码。
P.S我不知道如何通过引用传递变量,所以通过值来传递。

// This is your routine C++ code
size_t MyStrLen(std::string inStr) {
    return inStr.length();
}

// This is the extra code you need to write to expose your function to JS
EMSCRIPTEN_BINDINGS(my_module) {
    function("MyStrLen", &MyStrLen);
}

在JS中,你需要做的就是:

var myStr = "TestString";
Module.MyStrLen(myStr);

一定要把旗子递过去
--bind
呼叫emcc时。
有一个another approach,你可以从JS在C++堆上做一个Malloc,然后做操作,但是上面的方法应该更容易。

tsm1rwdh

tsm1rwdh2#

其他答案没有解决如何从C返回字符串。下面是一种通过引用传递一个字符串的方法,将一个字符串从c传递到JavaScript。
emscripten文档说明了可以使用cwrap/ccall传递给C/C++函数的类型(emscripten文档):
类型是“number”(对应于C整数、浮点数或通用指针的JavaScript数字)、“string”(对应于表示字符串的C char* 的JavaScript字符串)或“array”(对应于C数组的JavaScript数组或类型化数组;对于类型化数组,它必须是Uint 8Array或Int 8Array)。
正如其他答案所指出的,您需要使用C字符串作为参数来编写C函数,因为这是emscripten API(而不是因为extern "C")。
如果你想返回一个字符串,你可能认为你可以只传递一个C字符串(有效地通过引用,因为它是指针)并修改该字符串:

// 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

但是,这不起作用,因为在传递给函数时创建了一个副本。因此,您需要显式分配内存并传递指针。Emscripten为此提供了allocateUTF8UTF8ToString函数:

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

因为我们正在将字符串转换为字符指针,所以我们也可以直接调用该函数,而不使用cwrap(emscripten docs):Module._stringTest(ptr)。它需要一些额外的步骤,但现在你已经从C传递了一个字符串到JavaScript。
要使此示例正常工作,您可能需要使用以下标志进行编译:-sEXPORTED_FUNCTIONS="['_stringTest','_malloc','_free']"-sEXPORTED_RUNTIME_METHODS="['cwrap','allocateUTF8','UTF8ToString']"
还有更通用的方法为其他类型的数组(https://stackoverflow.com/a/23917034/12510953)分配内存。

roejwanj

roejwanj3#

几点想法:
1.我调用方法的唯一方法是使用crwapccall
var length = Module.ccall('stringLen', ['string'], 'number');
1.您是否在EXPORTED_FUNCTIONS参数中包含stringLenstringTest
emcc hello_world.cpp ... -s EXPORTED_FUNCTIONS=['_stringLen','_stringTest']
查看更多详情:
http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html
或者我的hello_world教程:
http://www.brightdigit.com/hello-emscripten/
希望能帮上忙。

ttvkxqim

ttvkxqim4#

extern“C”无法识别std::string。
你可能想试试这个:
Test.cpp

#include <emscripten.h>
#include <string.h>

extern "C" int stringLen(char* p)
        {
            return strlen(p);
        }

使用以下命令编译cpp代码:

emcc Test.cpp -s EXPORTED_FUNCTIONS="['_stringLen']

样本测试代码:
Test.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Hello World !</title>
        <script src="a.out.js"></script>
        <script>
             var strLenFunction =  Module.cwrap('stringLen', 'number', ['string']);
             var len1 = strLenFunction("hi.");  // alerts 3
             alert(len1);
             var len2 = strLenFunction("Hello World"); // alerts 11
             alert(len2);
        </script>
    </head>
</html>

相关问题