- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
对于一个小型Java项目,我需要与用C编写的现有代码进行交互,以便使事情变得容易(不幸的是,我不是C / C ++程序员。)我决定使用swig。
生成的包装器代码似乎可以正常工作。但是,当我调用一个应该为我提供以NULL分隔的字符串列表的函数时(如果我没有记错的话,这就是C函数应该返回的内容)包装的代码仅返回预期的第一个String值值列表。我假设Java中正确的返回数据类型将是字符串数组而不是字符串?此假设是否正确,是否可以通过在swig接口文件中指定typemap
来解决?还是我走错了路?
C头文件中的函数指出:
DllImport char *GetProjects dsproto((void));
public final static native String GetProjects();
最佳答案
解决方案1-Java
您可以通过多种方法来解决SWIG中的此问题。我从一个解决方案开始,该解决方案仅要求您编写一些Java(在SWIG接口内),然后自动应用该函数以使函数以所需的语义返回String[]
。
首先,我编写了一个小的test.h文件,使我们可以练习正在努力的类型图:
static const char *GetThings(void) {
return "Hello\0World\0This\0Is\0A\0Lot\0Of Strings\0";
}
\0
终止(最后一个隐含在C中的字符串常量中)。
%module test
%{
#include "test.h"
%}
%include <carrays.i>
%array_functions(signed char, ByteArray);
%apply SWIGTYPE* { const char *GetThings };
%pragma(java) moduleimports=%{
import java.util.ArrayList;
import java.io.ByteArrayOutputStream;
%}
%pragma(java) modulecode=%{
static private String[] pptr2array(long in, boolean owner) {
SWIGTYPE_p_signed_char raw=null;
try {
raw = new SWIGTYPE_p_signed_char(in, owner);
ArrayList<String> tmp = new ArrayList<String>();
int pos = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (ByteArray_getitem(raw, pos) != 0) {
byte c;
while ((c = ByteArray_getitem(raw, pos++)) != 0) {
bos.write(c);
}
tmp.add(bos.toString());
bos.reset();
}
return tmp.toArray(new String[tmp.size()]);
}
finally {
if (owner && null != raw) {
delete_ByteArray(raw);
}
}
}
%}
%typemap(jstype) const char *GetThings "String[]";
%typemap(javaout) const char *GetThings {
return pptr2array($jnicall, $owner);
}
%include "test.h"
char *
,尽管我们在函数
%apply
的情况下不得不打破它,因为我们不希望这种情况发生。对数组函数使用
signed char
可以得到我们想要的:Java中的
Byte
而不是
String
的映射。
String[]
。 javaout typemap解释了我们如何根据JNI调用返回的内容(
long
,因为我们故意停止将其包装为普通的以null结尾的字符串)进行转换,而是使用了一些我们在模块内部编写的额外Java (
pptr2array
)为我们完成这项工作。
pptr2array
内部,我们实际上是在每个String中逐字节构建输出数组。我使用
ArrayList
是因为我宁愿动态增长它,也不愿对输出进行两次传递。使用
ByteArrayOutputStream
是一种逐字节构建Byte数组的好方法,它有两个主要优点:
$owner
并指示是否希望我们使用
free()
从C函数返回的内存,请使用
%newobject
。请参见
discussion of $owner
in docs。
%module test
%{
#include "test.h"
#include <assert.h>
%}
%typemap(jni) const char *GetThings "jobjectArray";
%typemap(jtype) const char *GetThings "String[]";
%typemap(jstype) const char *GetThings "String[]";
%typemap(javaout) const char *GetThings {
return $jnicall;
}
%typemap(out) const char *GetThings {
size_t count = 0;
const char *pos = $1;
while (*pos) {
while (*pos++); // SKIP
++count;
}
$result = JCALL3(NewObjectArray, jenv, count, JCALL1(FindClass, jenv, "java/lang/String"), NULL);
pos = $1;
size_t idx = 0;
while (*pos) {
jobject str = JCALL1(NewStringUTF, jenv, pos);
assert(idx<count);
JCALL3(SetObjectArrayElement, jenv, $result, idx++, str);
while (*pos++); // SKIP
}
//free($1); // Iff you need to free the C function's return value
}
%include "test.h"
native
函数将返回什么返回类型,分别是Java和C(JNI)类型。 javaout类型映射变得更简单,它所做的就是将
String[]
作为
String[]
直接传递。
String[]
的Java数组。这是通过第一步来简单地计算出有多少元素来完成的。 (在C中,没有一种整齐的方法可以做到这一点)。然后在第二遍中,我们调用
NewStringUTF
并将其存储到我们先前创建的输出数组对象中的正确位置。所有JNI调用都使用SWIG特定的
JCALLx macros,这使得它们可以在C和C ++编译器中工作。此处实际上没有必要使用它们,但是进入它并不是一个坏习惯。
const char*
字符串文字,因此我们不会释放它)。
%module test
%{
#include "test.h"
%}
%rename(GetThings) GetThings_Wrapper;
%immutable;
%inline %{
typedef struct {
const char *str;
} StrArrHandle;
StrArrHandle GetThings_Wrapper() {
const StrArrHandle ret = {GetThings()};
return ret;
}
%}
%extend StrArrHandle {
const char *next() {
const char *ret = $self->str;
if (*ret)
$self->str += strlen(ret)+1;
else
ret = NULL;
return ret;
}
}
%ignore GetThings;
%include "test.h"
GetThings()
返回类型。现在,它返回一个中间类型,该中间类型仅存在于包装器
StrArrHandle
中。
%inline
声明和定义了一个额外的函数来包装对
GetThings()
的实际调用,并使用一个额外的类型来保存它返回的指针供以后使用。
%ignore
和
%rename
仍然声称我的包装函数称为
GetThings
(即使这不是为了避免在生成的C代码内部出现名称冲突)。我本可以跳过
%ignore
而不只是在文件底部添加
%include
,但基于这样的假设:在现实世界中,您也想包装此示例的头文件中可能有更多东西是可能更有用。
%extend
将方法添加到创建的包装器类型中,该方法将返回当前字符串(如果不在末尾)并前进光标。如果您有责任释放原始函数的返回值,则还希望保留该函数的副本,并使用
%extend
添加一个“析构函数”供SWIG在对象被垃圾回收时调用。
StrArrHandle
构造
%nodefaultctor
对象。 SWIG将为
str
的
StrArrHandle
成员生成一个吸气剂。
%immutable
阻止它生成设置器,这在这里根本没有意义。您可能只是使用
%ignore
忽略了它,或者将
StrArrHandle
拆分了出来,而不是使用
%inline
,而只是不告诉SWIG该成员。
StrArrHandle ret = test.GetThings();
for (String s = ret.next(); s != null; s = ret.next()) {
System.out.println(s);
}
%typemap(jstype) StrArrHandle "String[]";
%typemap(javaout) StrArrHandle {
$javaclassname tmp = new $javaclassname($jnicall, $owner);
// You could use the moduleimports pragma here too, this is just for example
java.util.ArrayList<String> out = new java.util.ArrayList<String>();
for (String s = tmp.next(); s != null; s = tmp.next()) {
out.add(s);
}
return out.toArray(new String[out.size()]);
}
关于java - SWIG从String作为Java中的String数组获取returntype,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37253529/
考虑这些免费的独立功能: std::vector& f(); //reference std::vector g(); //value /*const
在泛型api中,为什么有时类型参数写在返回类型之前,有时则不需要? 以下两个 Steam API 为例 Stream limit(long maxSize) 和 Stream map(Fun
有什么区别吗 @ResponseBody public Object method(etc..) { etc.. } 和 public @ResponseBody Object method(
TypeScript 2.8 中的新ReturnType是一项非常有用的功能,可让您提取特定函数的返回类型。 function foo(e: number): number { return
我正在使用 twilio-node pkg 并且有 fetch function : lookupResponse = await twilioClient.lookups.v1.phoneNumbe
为了提供一些背景知识,我正在创建一个小型依赖项注入(inject)器,但在将方法调用转换回它们的返回类型时遇到了问题。一个最小的例子是: public class MinimalExample {
我正在尝试使用 ReturnType 生成一个类型,该类型取决于对象上函数的返回类型。 这是对象: const foo = { bar: (): number => 1, quux: ():
我的初始代码如下,它允许我在执行 switch on action:ActionType 时根据 type 检测 data 的类型。 enum Actions { GET_MESSAGES,
我正在尝试输入以下函数: function foo(input, modifier, merge) { return merge(...modifier.map(m => m(input)))
我不明白为什么在下面的情况下Temp类型是never。我明白为什么它与 (...args: any) => infer R 兼容,但如何从中推断出类型 never ? // type ReturnTy
我不明白为什么在下面的情况下Temp类型是never。我明白为什么它与 (...args: any) => infer R 兼容,但如何从中推断出类型 never ? // type ReturnTy
我正在尝试使用 typescript 2.8 的新 conditional types ,(尚未发布版本 2.8.0-dev.20180307),我不知道这是错误还是误用。我的重点是我的声明 Mock
我正在尝试扩展 redux connect,以便它可以与特定的 reducer/state 一起用作装饰器,这可能不是必需的,因为 redux connect 可以用作装饰器,但我很好奇为什么我不能它
typescript 中有一个功能叫做 ReturnType这允许您推断特定函数的返回类型,就像这样 function arrayOf(item: string): string[] { retu
我已经开始研究 Typewriter,看看它是否符合我生成模型和 API 层的要求。 到目前为止,它正在生成模型,我让它生成某种 API 层,但是在使用 $ReturnType 时我遇到了问题,如示例
我在 Hibernate 中有一个映射类,它包含一个命名的 sql 查询,该查询计算某些搜索参数的整数的最小值。实际的查询非常复杂(所以我既不能将其写为标准,也不能在我的 Hibernate 版本中将
我在 Xcode 10.2.1 中使用 Swift 5 我在 UInt8 的扩展中有这个功能 编译器在第 5 行报错,unexpected non-void return value in void
我有一个对象的实例,我会扫描其上附有适当注释的 memberProperties。然后,我想根据它们的返回类型进行过滤。 例如,如果声明如下:class AutoValidatedThing : Au
GLfloat test = glm::dot(glm::vec3(1.0f,1.0f,1.0f),glm::vec3(1.0f,1.0f,1.0f)); 这可以编译并正常工作,但 Clion-IDE
我见过几个这种形式的语法示例(我在快速搜索柯里化(Currying)时看到了这个) func funcName(a: TypeOfA)(b: TypeOfB) -> returnType { r
我是一名优秀的程序员,十分优秀!