【问题标题】:Non-deterministic return values (string type) from calling native C++ functions through JNA通过 JNA 调用本机 C++ 函数的非确定性返回值(字符串类型)
【发布时间】:2015-05-23 16:13:05
【问题描述】:

问题描述:

我的项目是 JAVA,但我想调用一个 C++ 函数,它将一个字符串作为输入并在处理后输出另一个字符串。我应用JNA来做这个工作,String和char*是JAVA到C++的映射类型。(在处理过程中,我需要std::string作为中间类型,详细给出了简化代码。)

当输入字符串不长时,程序运行良好。然而,当我增加字符串的长度时(这里,我重复了“test sentence ...”6次),事情开始变得奇怪了。我可以看到字符串在 C++ 程序中传递(成功打印出来),但是我在 JAVA 中收到了一个空字符串,这意味着它无法返回字符串。更重要的是,每次执行的while循环次数都不一样(中断循环时打印出不同的计数)。

那么,

1.长度有什么问题? JNA 有什么限制吗?

2。我可以达到我的目标以及如何在 JNA 中正确传递字符串吗?(顺便说一句,我尝试过指针的东西,但它不起作用)

谢谢,这是我的代码和一些环境细节

C++ 端代码>>>>>>>>>>>test.cpp

#include<iostream>
using namespace std;
extern "C" __attribute__((visibility("default"))) const char* SeudoCall(const char* input); 
const char* SeudoCall(const char* str){
    std::string input(str);
    std::cout<<"in C:"<<input<<std::endl;
    return input.c_str();
}

编译 C++ 库>>>>>>>>>

g++ test.cpp -fpic -shared -o libtest.so

JAVA 端代码>>>>>>>>>>

import com.sun.jna.Library;
import com.sun.jna.Native;
public class TestSo {
    public interface LgetLib extends Library {
        LgetLib INSTANCE = (LgetLib) Native.loadLibrary("test", LgetLib.class);
        String SeudoCall(String input);
    }
    public String SeudoCall(String input){
        return LgetLib.INSTANCE.SeudoCall(input);
    }
    public static void main(String[] args) {
        TestSo ts = new TestSo();
        String str = "test sentence...test sentence...test sentence...test sentence...test sentence...test sentence...";
        String retString;
        int count=0;
        while(true){
            System.out.println("count:"+(++count));
            retString=ts.SeudoCall(str);
            System.out.println("in JAVA:"+retString);
            if(retString.equals("")){
                System.out.println("break");
                break;
            }
        }
    }
}

运行细节>>>>>>>>>>

Intel Core i7-4790 3.60GHz
gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)
JNA 4.1.0
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)

【问题讨论】:

    标签: java c++ string jna


    【解决方案1】:

    您的 C++ 代码马上就有问题。您正在返回一个指向本地 std::string 的指针,该指针将在函数存在时被销毁。因此,您正在引入未定义的行为。

    换句话说,即使应用程序都是 C++,你的函数也会有问题,所以这不仅仅是 Java/JNA/C++ 问题,而是 C++ 本身的问题。

    const char* SeudoCall(const char* str){
        std::string input(str);
        std::cout<<"in C:"<<input<<std::endl;
        return input.c_str();  // <-- this is no good.
    }
    

    c_str() 绑定到局部变量 input。当函数退出时,input 的析构函数发生,同时带有代表字符串的c_str()

    要解决此问题,您必须将一个字符串返回给 Java,该字符串将在函数返回后“活动”。我不知道 JNA,但对于 JNI,您可以使用 JNI NewStringUTF 函数创建一个字符串,该字符串将作为 jstring 返回。

    也许这个链接会对你有所帮助:

    How to return char * aarr= new char[200] from C++ to Java using JNA

    当输入字符串不长时,程序运行良好。然而, 当我增加字符串的长度时(在这里,我复制了“测试 句子...” 6次),事情开始变得奇怪。我可以看到字符串 是通过 C++ 程序(成功打印出来),但我收到了 JAVA中的空字符串,这意味着它无法返回字符串。 更重要的是,每个while循环的时间都不一样 执行(中断循环时打印出不同的计数)。

    您所看到的是未定义的行为。从您的 C++ 函数返回的指针可能指向保存字符的内存,但不能依赖它,因为您的测试向您展示。

    【讨论】:

    • 我试图在JAVA端向C++程序发送一个字节[]分配内存,并在C++中更改它的内容,以便在调用C++后使其保持活动状态。尽管如此,当字符串变长时,JVM 还是崩溃了。
    • 非常感谢!正如您提到的,我通过用 JNI 替换 JNA 来解决它,但是速度变慢了。是 GetStringUTFChars、ReleaseStringUTFChars 还是 NewStringUTF 的性能造成的?
    • 确保您正在运行代码的发布版本,而不是调试版本。我不熟悉JNA,所以无法告诉你速度比较的差异。
    猜你喜欢
    • 2012-12-12
    • 2016-05-04
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 2014-12-12
    • 1970-01-01
    • 2012-09-16
    相关资源
    最近更新 更多