如何通过emscripten在C++和javascript之间传递字符串
How to pass strings between C++ and javascript via emscripten
我正在学习emscripten,在C++和JS之间传递字符串时,我甚至无法进行最基本的字符串操作。
例如,我想写一个字符串长度函数。在C++中:
extern "C" int stringLen(std::string p)
{
return p.length();
}
从javascript调用为:
var len = _stringLen("hi.");
这为我产生了0
。我如何使它按预期工作?我应该在这里使用哪种字符串类型?char const*
?std::wstring
?std::string
?似乎都不起作用;我总是得到非常随机的值。
这只是一个开始。。。然后我如何从C++返回这样的字符串?
extern "C" char *stringTest()
{
return "...";
}
在JS中:
var str = _stringTest();
再说一遍,我找不到一种方法来实现这一点;我总是在JS中收到垃圾。
所以我的问题很清楚:如何通过Emscripten在JS和C++之间封送字符串类型?
extern"C"无法识别std::字符串。
你可能想试试这个:
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>
如果在函数中使用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);
确保你通过标志
-绑定
调用emcc时。
还有另一种方法,您可以从JS在C++堆上执行Malloc,然后进行操作,但上述方法应该更容易。
其他答案没有涉及如何从C++返回字符串。以下是一种通过引用传递字符串将字符串从c++传递到javascript的方法。
emscripten文档说明了可以使用cwrap
/ccall
(emscripten docs)传递给C/C++函数的类型:
类型为";数字";(对于对应于C整数、浮点或通用指针的JavaScript数字),";字符串";(对于对应于表示字符串的C字符*的JavaScript字符串)或";阵列";(对于JavaScript数组或与C数组相对应的类型化数组;对于类型化数组,它必须是Uint8Array或Int8Array)。
正如其他答案所指出的,您需要使用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为此提供allocateUTF8
和UTF8ToString
功能:
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)。
几个想法:
- 我调用方法的唯一方法是使用
crwap
或ccall
var length = Module.ccall('stringLen', ['string'], 'number');
- 您的
EXPORTED_FUNCTIONS
参数中是否包括stringLen
和stringTest
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/
希望这能有所帮助。
- C++ 使用 assign 函数的字符串与直接使用 '=' 更改值的字符串之间的区别
- 我已经建立了递归关系,它找到了两个字符串之间最长的连续公共字符串,我怎么能跳过其中一个字符串中的一个字符
- 编辑字符串以包含括号 c++ 之间的变量
- 同一分隔符之间的多个子字符串
- 在.cpp文件之间传递全局字符串变量?
- 我的 c++ 程序似乎没有发现字符串和我拥有但输入使用 getline 的变量之间的比较
- 如何在 的开头<x>和结尾<y>之间更改带有文件输出的字符串的值
- 两个字符串之间的数学运算
- 在 Rcpp 中的字符串类型之间转换时出错
- 如何排列二进制字符串以最小化它们之间的距离
- 目标是找到两个 c 字符串之间的公共前缀(必须使用特定的函数标头)
- 我需要在C++的两个字符串之间找到共同的前缀
- 打印C++中字符出现之间/之后的所有子字符串
- 使用正则表达式c++从单词和分隔符之间的字符串中提取所有子字符串
- C++获取两个分隔符之间的字符串并替换它
- 如何在没有映射的情况下在枚举和字符串之间进行转换?
- 正则表达式匹配字符串之间的数字
- 有序地图字符串搜索与整数搜索之间的时间复杂度
- C++ 复制字符串的指定索引之间的任何子字符串
- 匹配外部单引号之间的字符串