如何将状态和byte []从C ++返回到Java

时间:2012-11-21 18:13:33

标签: java c++ java-native-interface

我有一个带有以下签名的C ++方法:

int cppGetData(string& data);

应该从Java方法调用它。

版本I

byte[] javaGetData();

如果null返回非零返回码,则返回cppGetData

我明白我必须写这样的东西:

JNIEXPORT jbyteArray JNICALL jniGetData(JNIEnv * env, jobject thisObj) 
(
  string data;
  if (cppGetData(data))
  {
    return NULL;
  }

  jbyteArray jData = env->NewByteArray(data.size());
  env->SetByteArrayRegion(jData, 0, data.size(), (jbyte *)data.c_str());

  return jData;
}

我的问题是我失去了cppGetData返回的状态。另一方面,Java没有引用返回,所以我很困惑。如何返回byte[]和整数状态?

当然,我可以有一个包装器,类似这样:

public class ByteArrayWrapper{
  public byte[] bytes;
}

然后javaGetData变为:

int javaGetData(ByteArrayWrapper wrapper);

这太糟糕了。无论是在API签名方面还是在jniGetData方法复杂性方面。

有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

最接近你的工作是

native static int cppGetData(ByteBuffer bb);

这比你所拥有的要好得多,因为ByteBuffer是byte []的包装器,但它使用内置类来完成它。一个限制是底层字节[]不可调整大小,但你可以通过设置limit来缩小它。

另一种选择是使用

native static int cppGetData(byte[][] bytes)

这允许您返回不同的字节[]。

或者你可以

int[] num = { 0 };

native static byte[] cppGetData(int[] num)

或更新对象的字段,如

class CallsCppGetData {
    int num;
    byte[] bytes;

    native void cppGetData(); // sets this.num and this.bytes.
}

返回多个值的解决方案是使用对象。

你要么

  • 更新您正在调用该方法的对象的多个字段。
  • 包装多个字段时返回一个对象。
  • 传递一个可变对象进行设置。例如你可以传递一个int[],它有一个元素。

虽然创建新类很糟糕,但是有一个方法而不是一个结果。 ;)

答案 1 :(得分:0)

如果传递一个对象是一个问题,我只看到另一个解决方案:有两个单独的方法

jint prepareData();
jbyteArray getData();

如果您指定的话,第二个只在第一个返回零时调用。当然,这种解决方案并不特别原子,因为它需要在C侧的呼叫之间存储持久数据。除非你在Java端将同步块中的两个本机调用包装起来。但是,许多无处不在的框架在其他函数调用之后无畏地使用这种技术来报告一些常见的内部状态。我想到了Win32 API GetLastError,虽然它是线程安全的。