【发布时间】:2012-06-14 04:30:25
【问题描述】:
如何使用 Java 处理从本机库接收的 va_list 参数?
我正在使用一个有助于通过回调函数进行日志记录的 C 库。该库是libghoto2,我正在使用JNA 包装器libgphoto2-java 来访问它的功能。
请参阅this C file 中的errordumper 方法,了解如何进行日志记录的示例。
我已经设法使用库的gp_log_add_func 添加了一个Java 编写的回调函数。唯一的问题是,回调函数的签名包含一个我不知道如何处理的va_list 参数。
正如C example from earlier 所示,va_list args 直接传递给vfprintf。阅读vfprintf manual 可以清楚地看出它是某种“已使用va_start 宏初始化”的可迭代数据结构,并且在使用va_arg 进行迭代之后,需要使用va_end 进行清理。
但我发现防止 JVM 崩溃的唯一方法是设置 com.sun.jna.Pointer 类型的 args 参数,而 String[] 或 Object[] 会更合适。
如何从这个 va_list 中获取数据?
注意为了访问gp_log_add_func,我添加了一些Java代码:
org.gphoto2.jna.GPhoto2Native的补充:
int gp_log_add_func(int logLevel, LogFunc func, Pointer data);
创建org.gphoto2.jna.LogFunc:
public interface LogFunc extends Callback {
public static final int GP_LOG_ERROR = 0;
public static final int GP_LOG_VERBOSE = 1;
public static final int GP_LOG_DEBUG = 2;
public static final int GP_LOG_DATA = 3;
public static final int GP_LOG_ALL = GP_LOG_DATA;
//the args argument is a va_list
public void log(int logLevel, String domain, String format, Pointer args, Pointer data);
}
org.gphoto2.jna.LogFunc的实现和使用:
LogFunc callback = new LogFunc() {
public void log(int logLevel, String domain, String format, Pointer args, Pointer data) {
System.out.println("[" + domain + "] " + format);
System.out.println(args.toString());
}
};
GPhoto2Native.INSTANCE.gp_log_add_func(LogFunc.GP_LOG_ALL, callback, null);
【问题讨论】:
-
您必须查看相关平台上 va_list 的实际实现(从头文件 (vararg.h) 开始,并可能深入研究编译器细节)。 va_list通常是一个指向堆栈的指针,各种提取参数只是将指针移动适当大小的偏移量的偏移操作。您必须使用指针手动提取内容,使用各种数据提取方法,如 Pointer.getInt(int offset),具体取决于您尝试访问的类型。
-
这就是我害怕的。从纯粹主义者的角度来看,JNA/Java 业务应该与任何本地业务分开。这尤其令人担忧,因为我目前正在 openSuse 上进行开发,以后可能想在 OS X 上进行部署。不幸的是,我对 C/C++ 了解不多,但可能有一种方法可以使用第二个本机库来转换 va_list进入更易于 JNA 管理的东西?
-
JNA 应该为 va_list 处理提供映射当然是一个有争议的案例。随意打开一个问题。
-
今天我又有了一些空闲时间来做这件事;我想我可能已经找到了一种方法来提取数据并将整个东西变成一个 Java List
-
如果你有 va_start(va_list 地址)的结果,你可以使用指针函数来执行 va_arg 的等价(va_end 不可能做任何事情)。获取可变参数的地址是困难的部分。
标签: java callback jna variadic-functions libgphoto2