2

ネイティブ ライブラリから受け取った va_list 引数を Java で処理するにはどうすればよいですか?

コールバック関数によるロギングを容易にする C ライブラリを使用しています。ライブラリはlibgoto2で、JNA ラッパーlibgphoto2-javaを使用してその機能にアクセスしています。ロギングの実行方法の例については、この C ファイルerrordumperのメソッドを参照してください。

ライブラリのgp_log_add_func. 唯一の問題は、コールバック関数の署名va_listに処理方法がわからない引数が含まれていることです。

前に示したC の例のようva_list argsに、は に直接渡されvfprintfます。vfprintfマニュアルを読むと、 va_start「マクロで初期化された」ある種の反復可能なデータ構造でありva_arg、クリーンアップを使用して反復した後にva_end必要であることが明らかになります。しかし、JVM がクラッシュしないようにするために私が見つけた唯一の方法はargs、型のパラメーターをcom.sun.jna.Pointeror の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);
4

2 に答える 2

2

以下は varargs の実装例で、varargs マクロが何をしているかについてのいくつかのヒントがあります:

int printf(const char* fmt, ...) {
  va_list argp;

  va_start(argp, fmt); // usually something like: argp = (char *)&fmt - sizeof(void *);

  int arg1 = va_arg(argp, int); // *(int *)argp; argp += sizeof(int);
  void *arg2 = va_arg(argp, void*); // *(void **)argp; argp += sizeof(void *);
  float arg3 = va_arg(argp, float); // *(float *)argp; argp += sizeof(float);

  va_end(argp); // no-op

}

つまり、基本的には、スタック ポインターを操作する一連のポインター演算です。JNA の問題点は、スタック ポインターにアクセスできないことです。おそらく、JNA のコールバック メカニズムをネイティブ レベルで拡張して、可変引数コールバックを特別に処理してスタック ポインターを提供する必要があります。

それでも問題になる可能性があります。上記の例からわかるように、可変引数にアクセスするには、可変引数関数シグネチャの最後の名前付き引数のアドレスが実際に必要です。これを一般的に行うのは非常に難しいでしょう。

于 2012-07-12T22:41:53.710 に答える