从Java传递字符串到JNI

27

我想将一个字符串传递到我正在编写的JNI中,该字符串必须分配给const char *。 以下是我的做法:

JNI...(...,jstring jstr...){

const char* str = env->GetStringUTFChars(jstr,0);
env->ReleaseStringUTFChars(str,jstr,0);

}

但是如果我在将 const char* str 赋值给 jstring 后使用 printf,与我直接在 JNI 中赋值 str 值并从那里 printf 所看到的不同。

这是正确的做法吗?还是有其他方法将字符串从 Java 分配给 JNI 中的 const char*?


你能提供在Java之前和在C之后的字符串吗? - dacwe
关于您的 ReleaseStringUTFChars 的参数与文档不符。 - Leponzo
6个回答

40

Java代码

public static native double myMethod( String path);  

C 代码

JNIEXPORT jdouble JNICALL Java_your_package_structure_className_myMethod
(JNIEnv * env, jobject jobj, jstring pathObj) {
     char * path;

    path = (*env)->GetStringUTFChars( env, pathObj, NULL ) ;

4
这里有多个错误。首先,如果方法是静态的,则没有jobject,而是jclass。其次,(*env)是不正确的,只需要使用env->Get...。第三,GetStringUTFChars不会将env作为参数传递进去。 - Vladimir Ivanov
2
@Vladimir Ivano,请查看文档,这是可行的代码 http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jnistring.html - jmj
16
@VladimirIvanov 这个 (*env)->Method(env, 是 C 语言中 JNI 的写法,而 env-> 则是 C++ 中 JNI 的写法。 - gub
1
你真是让我开心啊!我已经尝试了4个小时,所有类似的解决方案都没有用,但这一个却行了!非常感谢你!! - Rizwan Sohaib
8
参考链接似乎已经失效。 - Denys Kniazhev-Support Ukraine
显示剩余3条评论

3
JNIEXPORT jstring JNICALL Java_Hello_sayHi(JNIEnv *env, jobject obj, jstring string) {
     const char *str = env->GetStringUTFChars(string, 0);
     printf("%s", str);
}

你可以试一下这个方法,肯定会有帮助的。 - prem kumar
1
你应该始终提供解释来支持你的答案。 - Balwinder Singh
欢迎来到Stack Overflow!虽然这段代码可能解决了问题,但是包括解释可以真正帮助提高您的帖子质量。请记住,您正在为将来的读者回答问题,而那些人可能不知道您建议代码的原因。此外,请尽量不要在代码中加入说明性注释,这会降低代码和解释的可读性! - Filnor

2

您所做的一切都是正确的。 除了获取char之外,还有另一种方法:获取wchar_t:

const wchar_t * utf16 = (wchar_t *)env->GetStringChars(bytes, NULL);
size_t length = (size_t)env->GetStringLength(bytes);        
...
env->ReleaseStringChars(bytes, (jchar *)utf16);

0

正如 #Jigar 所解释的:

JNIEXPORT jdouble JNICALL Java_your_package_structure_className_myMethod
(JNIEnv * env, jobject jobj, jstring jstr) {


    const char *path = (*env)->GetStringUTFChars( env, jstr , NULL ) ;

为了从Java获取jstring,应该编写如下的C++方法。
C++代码:
const char *path = env->GetStringUTFChars(jstr , NULL ) ;

更新: 如评论中所述,代码中存在错误。现已修复。


在您的 C 版本中,pathchar *,而在您的 C++ 版本中,pathconst char* - 我感到困惑 - 用户是否应该释放字符数组,还是它是指向某个内部 jstring 字段的指针,将由 Java 处理? - SomethingSomething
@SomethingSomething 感谢您的关注。问题已经解决。 - Davood Falahati

0
there are several ways but the best i got by converting const char * to c++ string 
and then to jbyteArray, and its easy to conversion of byteArray to UTF-8 on java 
side.

C++ side:
const char* string = propertyValue;
std::string str = string;

jbyteArray array = env->NewByteArray(str.length());
env->SetByteArrayRegion(array,0,str.length(),(jbyte*)str.c_str());


return array;

java/kotlin side:

String((array), Charset.defaultCharset()))

-1
其实解决方案很简单:使用"GetStringUTFChars"函数的最后一个参数为JNI_TRUE来发送拷贝。由于您传递了JNI_FALSE (0) 并调用了"ReleaseStringUTFChars",因此您正在销毁该引用。您在“释放”后看到的是应用程序内存中其他位置的随机字节。
使用JNI_TRUE调用"GetStringUTFChars"或删除"ReleaseStringUTFChars"调用都会解决您的问题。
编辑:对不起,我犯了错误。

真的吗?str 的值如何神奇地改变,指向应用程序内存中的其他地址? - user207421
据我所知,他说的是“const char *”的内容发生了变化,而不是指针本身。 - Eduardo Costa
我在谈论你所说的:“从应用程序内存中的其他位置获取随机字节”。这意味着str的值已更改,但由于它不是通过引用传递的,所以这是不可能的。 - user207421
1
这是一个C指针。在释放之前,它指向一些有用的东西。如果你释放并保留它,它就成为指向内存中其他东西的指针。如果你在C中写下'char a; char * b = &a + rand() % 10000; printf("%s\n", b);',你会得到他描述的相同症状(以及我所说的“随机”,因为你无法预测它是什么)。 - Eduardo Costa
2
-1 "GetStringUTFChars" 的最后一个参数是输出值(指向布尔值的指针)。无论您传入什么,它只是告诉您是否为副本(请参阅 http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html 上的文档)。 此外,如果您删除了“ReleaseStringUTFChars”,则会向应用程序添加内存泄漏。应该在调用释放函数之前充分利用数据,或在释放之前复制数据。 - Grant Peters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接