Java 如何从C+;返回状态和字节[]+;到爪哇 我有一个C++方法,有以下签名: int cppGetData(string& data);

Java 如何从C+;返回状态和字节[]+;到爪哇 我有一个C++方法,有以下签名: int cppGetData(string& data);,java,c++,java-native-interface,Java,C++,Java Native Interface,应该从Java方法调用它 第一版: byte[] javaGetData(); 如果cppGetData返回非零返回代码,则应返回null 我知道我必须写这样的东西: JNIEXPORT jbyteArray JNICALL jniGetData(JNIEnv * env, jobject thisObj) ( string data; if (cppGetData(data)) { return NULL; } jbyteArray jData = env-&

应该从Java方法调用它

第一版

byte[] javaGetData();
如果
cppGetData
返回非零返回代码,则应返回
null

我知道我必须写这样的东西:

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;
}
public class ByteArrayWrapper{
  public byte[] bytes;
}
我的问题是我失去了
cppGetData
返回的状态。另一方面,Java没有引用返回,所以我感到困惑。如何返回
字节[]
和整数状态

当然,我可以有一个包装纸,像这样:

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;
}
public class ByteArrayWrapper{
  public byte[] bytes;
}
然后javaGetData变成:

int javaGetData(ByteArrayWrapper wrapper);
这太糟糕了。就API签名和方法复杂性而言


有更好的方法吗?

最接近你的方法是

native static int cppGetData(ByteBuffer bb);
这并不比ByteBuffer是字节[]的包装器好多少,但它使用内置类来完成。一个限制是基础字节[]不可调整大小,但您可以通过设置
限制
使其变小

另一个选择是使用

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

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

要么你

  • 更新正在调用方法的对象的多个字段
  • 包装多个字段时返回一个对象
  • 传递要设置的可变对象。e、 g.您可以传递一个包含一个元素的
    int[]

虽然创建新类很糟糕,但拥有一个没有多个结果的方法也很糟糕

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

jint prepareData();
jbyteArray getData();

如您所指定,仅当第一个返回零时才调用第二个。当然,这个解决方案并不特别原子化,也不安全,因为它需要在C端的调用之间存储持久数据。除非将两个本机调用都包装在Java端的同步块中。但是,许多无处不在的框架在其他函数调用之后大胆地使用这种技术来报告一些常见的内部状态。Win32 API <代码> GETLASTORKEXE/EXCUT>,虽然这是线程安全的。< /P>如果错误代码为非零,您只需抛出异常,那么,您真的想要C++ >代码>字符串< /COD> > java <代码>字节[] /代码>?或者您想在这里使用
jstring
?问题是我必须使用JNI更新对象。这是一个真正的皮塔。