如何修改传递给 C++ 的 jstring 的值使用 Java 和 JNI 的例程?

发布于 2024-12-03 13:49:43 字数 354 浏览 1 评论 0原文

我可以使用 JNI 函数调用将字符串从 Java 传递到我的 C++ 例程并在 C++ 例程中修改其值吗?

到目前为止,我已经看到了返回 jstring 的示例,但我不想这样做。我知道的另一个选项是获取 C++ 中字符串变量的 ID 并设置其值。

目前,我正在使用如下所示的函数:

JNIEXPORT void JNICALL Java_myexample_ChangeString
(JNIEnv *, jobject obj, jstring strJava) 

我想更改 strJava 的值。所以,本质上我要问的是Java是否可以通过引用而不只是通过值传递变量。

谢谢。

Can I pass a string from Java to my C++ routine using JNI function calls and modify its value in the C++ routine?

So far, I have seen examples of returning jstring, which I do not want to do. The other option that I know about is to get the ID of the string variable within C++ and set its value.

At present, I am playing with a function like the following:

JNIEXPORT void JNICALL Java_myexample_ChangeString
(JNIEnv *, jobject obj, jstring strJava) 

And I want to change strJava's value. So, essentially what I am asking is if it Java can pass variables by reference and not just by value.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眸中客 2024-12-10 13:49:43

Java 字符串在设计上是不可变的,您无法更改它们,即使使用 JNI 也是如此。

Java strings are immutable by design, you cannot change them, not even with JNI.

恬淡成诗 2024-12-10 13:49:43

因此,看来您真正想要做的是从本机方法返回多个值。没有直接的方法可以做到这一点,但有一些间接的方法:

  • 创建一个包含 boolean的类,而不是返回 boolean String,并让您的本机代码创建并返回该类的实例。
  • 传递一个单元素 String[] 作为参数,并让本机代码将其字符串结果设置为该数组的第一个元素。
  • 使用 #setStringValue(String) 方法创建一个类,并将其传递到本机方法中,然后该方法将调用该方法来提供字符串结果。一旦本机调用完成,创建帮助器类的 Java 代码就可以提取字符串值。

在这些可能性中,单元素数组可能是最容易通过 JNI 代码处理的,因为它不涉及查找其他类或方法。但是,如果我想从非本机方法返回额外信息,我可能会返回包含这两个结果的新类的实例。

So, it seems that what you really want to do is return more than one value from a native method. There is no direct way to do this, but there are a few indirect ways:

  • Instead of returning a boolean, create a class that contains both a boolean and a String, and have your native code create and return an instance of that class.
  • Pass a one-element String[] as an argument, and have the native code set its string result as the first element of that array.
  • Create a class with a #setStringValue(String) method, and pass that into your native method, which will then call that method to supply the string result. Once the native call completes, the Java code that created the helper class can extract the string value.

Of these possibilities, the one-element array is probably the easiest to handle from JNI code because it doesn't involve looking up additional classes or methods. However, if I wanted to return extra information from a non-native method I would probably return an instance of a new class containing both results.

卸妝后依然美 2024-12-10 13:49:43

您不能直接修改 String 参数,因为 Java String 是不可变的。但是,您可以做的是将字符串放入数组中,将数组传递给本机代码,然后在本机代码中(使用一些 JNI 互操作方法)创建一个新的 Java String 并替换引用在数组中引用新字符串:

Caller.java:

package com.mycompany.myapp;

// Prototype for native method.
class MyJNI {
    public static native void changeStringsNative(String[] stringArr);
}

void CallNative()
{
    String[] myStringArr = new String[1] {"Original"};
    System.out.println("Original (Java): " + myStringArr[0]);
    MyJNI.changeStringsNative(myStringArr);
    System.out.println("Changed (Java): " + myStringArr[0]);
}

Callee.c

#include <jni.h>
#include <stdio.h>

// Helper macro so we only need to declare class name once.
#define JNIFUNCTION(sig) Java_com_mycompany_myapp_MyJNI##sig

JNIEXPORT void JNICALL JNIFUNCTION(changeStringsNative(JNIEnv *env, jobject obj,
    jobjectArray myStringArr))
{
    int stringCount = env->GetArrayLength(myStringArr);
    for (int i = 0; i < stringCount; i++) {
        jstring myString = (jstring)(env->GetObjectArrayElement(myStringArr, i));
        const char *myStringOriginalC = env->GetStringUTFChars(myString, NULL);
        printtf("Original (native): %s\n", myStringOriginalC);
        env->ReleaseStringUTFChars(myString, myStringOriginalC);
        
        // Now do something in native to transform the string. For example, a printf involving the original.
        char *myStringChangedC = NULL;
        if (asprintf(&myStringChangedC, "Different from the %s!\n", myStringOriginalC) == -1) {
            // asprintf malloc error.
            return;
        }
        printtf("Changed (native): %s\n", myChangedStringC);

        // Create a new jstring and put into the array.
        env->SetObjectArrayElement(myStringArr, i, env->NewStringUTF(myChangedStringC));

        free(myStringChangedC); // must free after asprintf's malloc.
    }
    return true;
}

输出到 stdout:

Original (Java): Original
Original (native): Original
Changed (native): Different from the Original!
Changed (Java): Different from the Original!

You can't directly modify a String parameter, as Java Strings are immutable. What you can do however is place the string in an array, pass the array to the native code, and then in the native code (using some JNI interop methods) create a new Java String and replace the reference in the array with a reference to the new string:

Caller.java:

package com.mycompany.myapp;

// Prototype for native method.
class MyJNI {
    public static native void changeStringsNative(String[] stringArr);
}

void CallNative()
{
    String[] myStringArr = new String[1] {"Original"};
    System.out.println("Original (Java): " + myStringArr[0]);
    MyJNI.changeStringsNative(myStringArr);
    System.out.println("Changed (Java): " + myStringArr[0]);
}

Callee.c

#include <jni.h>
#include <stdio.h>

// Helper macro so we only need to declare class name once.
#define JNIFUNCTION(sig) Java_com_mycompany_myapp_MyJNI##sig

JNIEXPORT void JNICALL JNIFUNCTION(changeStringsNative(JNIEnv *env, jobject obj,
    jobjectArray myStringArr))
{
    int stringCount = env->GetArrayLength(myStringArr);
    for (int i = 0; i < stringCount; i++) {
        jstring myString = (jstring)(env->GetObjectArrayElement(myStringArr, i));
        const char *myStringOriginalC = env->GetStringUTFChars(myString, NULL);
        printtf("Original (native): %s\n", myStringOriginalC);
        env->ReleaseStringUTFChars(myString, myStringOriginalC);
        
        // Now do something in native to transform the string. For example, a printf involving the original.
        char *myStringChangedC = NULL;
        if (asprintf(&myStringChangedC, "Different from the %s!\n", myStringOriginalC) == -1) {
            // asprintf malloc error.
            return;
        }
        printtf("Changed (native): %s\n", myChangedStringC);

        // Create a new jstring and put into the array.
        env->SetObjectArrayElement(myStringArr, i, env->NewStringUTF(myChangedStringC));

        free(myStringChangedC); // must free after asprintf's malloc.
    }
    return true;
}

Output to stdout:

Original (Java): Original
Original (native): Original
Changed (native): Different from the Original!
Changed (Java): Different from the Original!
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文