通过JNA调用本机C ++函数的非确定性返回值(字符串类型)

时间:2015-05-23 16:13:06

标签: java c++ string jna

问题描述:

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

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

然后,

1。长度有什么问题? JNA有任何限制吗?

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

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

C ++ SIDE上的代码>>>>>>>>>>>> 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();
}

COMPILE C ++ LIBRARY&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;

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

JAVA SIDE上的代码&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;

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;
            }
        }
    }
}

RUN DETAIL&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;

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)

1 个答案:

答案 0 :(得分: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,这将是&#34; alive&#34;函数返回后。我不知道JNA,但对于JNI,您使用JNI NewStringUTF函数创建一个将作为jstring返回的字符串。

也许这个链接可以帮到你:

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

  

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

您目睹的是未定义的行为。从C ++函数返回的指针可能指向包含字符的内存,但不会依赖它,因为您的测试正在向您显示。