在我的Android JNI代码中,我需要将jstring转换为wchar_t。我发现的最近参考是How do I convert jstring to wchar_t *。
可以使用以下代码获取jchar *和长度:
const jchar *raw = env->GetStringChars(string, 0);
jsize len = env->GetStringLength(string);
wchar_t* wStr = new wchar_t[len+1];
似乎我不能使用wcncpy复制" raw"进入" wStr。"虽然jchar的长度为2个字节,但在所有现代版本的Android OS上,wchar_t的长度为4个字节。
一种选择是在for循环中一次复制一个字符:
for(int i=0;i<len;i++) {
wStr[i] = raw[i];
}
wStr[len] = 0;
另一种选择是调用env-&gt; GetStringUTFChars()并使用iconv_ *例程转换为wchar_t类型。
有人可以确认选项1是否有效?希望我不必诉诸于选项2.有更好的选择吗?问候。
答案 0 :(得分:1)
wchar_t
指定元素大小,但不指定字符集或编码。既然你问的是32位元素,我们可以假设你想使用Unicode / UTF-32吗?无论如何,一旦确定了所需的编码,标准Java库就可以完成任务。
使用String.getBytes()重载来获取字节数组。 (如果你有选择的话,在Java而不是JNI中更容易做到这一点。)一旦有了jbyteArray,就可以将它复制到C缓冲区并转换为wchar_t *
。
在Android上,您可能需要Unicode / UTF-8。但是它有一个8位代码单元,所以你可能不会问wchar_t
。 (BTW- UTF-8中的字符可能需要1个或更多字节。)
答案 1 :(得分:1)
一种方法是使用String.getBytes("UTF-32LE")
。注意这是假设wchar_t
是4个字节和小端的假设,但这应该是一个相当安全的假设。
这是一个将String从Java传递到C ++的示例,它将转换为std :: wstring,反转并传递回Java:
class MyClass {
private native byte[] reverseString(byte[] arr);
String reverseString(String s) {
try {
return new String(reverseString(s.getBytes("UTF-32")), "UTF-32");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "";
}
}
}
在C ++方面你有:
std::wstring toWStr(JNIEnv *env, jbyteArray s)
{
const wchar_t *buf = (wchar_t*) env->GetByteArrayElements(s, NULL);
int n = env->GetArrayLength(s) / sizeof(wchar_t);
// First byte is BOM (0xfeff), so we skip it, hence the "buf + 1".
// There IS NO null-terminator.
std::wstring ret(buf + 1, buf + n);
env->ReleaseByteArrayElements(s, (jbyte*) buf, 0);
return ret;
}
jbyteArray fromWStr(JNIEnv *env, const std::wstring &s)
{
jbyteArray ret = env->NewByteArray((s.size()+1)*sizeof(wchar_t));
// Add the BOM in front.
wchar_t bom = 0xfeff;
env->SetByteArrayRegion(ret, 0, sizeof(wchar_t), (const jbyte*) &bom);
env->SetByteArrayRegion(ret, sizeof(wchar_t), s.size()*sizeof(wchar_t), (const jbyte*) s.c_str());
return ret;
}
extern "C" JNIEXPORT jbyteArray JNICALL Java_MyClass_reverseString(JNIEnv *env, jobject thiz, jbyteArray arr)
{
std::wstring s= toWStr(env, arr);
std::reverse(s.begin(), s.end());
return fromWStr(env, s);
}
我在手机上测试了它,它有Android 4.1.2和ARM CPU,在Android模拟器上测试 - Android 4.4.2和x86 CPU,以及此代码:
MyClass obj = new MyClass();
Log.d("test", obj.reverseString("hello, здравствуйте, 您好, こんにちは"));
给出了这个输出:
06-04 17:18:20.605: D/test(8285): はちにんこ ,好您 ,етйувтсвардз ,olleh
答案 2 :(得分:0)
只要您的所有数据都是UCS2,就可以使用选项1 。有关类似的讨论,请参阅 wchar_t for UTF-16 on Linux? 。请注意,C ++ 11提供了std::codecvt_utf16来处理这种情况。
答案 3 :(得分:-1)
无需转换。将const jchar
投射到(wchar_t *)
。 jni.h将jchar定义为typedef uint16_t jchar; /* unsigned 16 bits */
,最终为wchar_t
。
你可以试试这个,它在旧项目中对我有用。