2012-06-11 3 views
1

Java에서 va_list 인수를 처리 할 수 ​​있습니까? 네이티브 라이브러리에서 va_list 인수를 수신 했습니까?JNA 콜백 함수의 va_list 인수 처리

콜백 기능을 통한 로깅을 용이하게하는 C 라이브러리를 사용하고 있습니다. 라이브러리는 libghoto2이고 JNA 랩퍼 libgphoto2-java을 사용하여 해당 기능에 액세스합니다. 로깅을 수행하는 방법의 예는 this C fileerrordumper 방법을 참조하십시오.

라이브러리의 gp_log_add_func을 사용하여 Java 작성 콜백 함수를 추가 할 수있었습니다. 유일한 문제는 콜백 함수의 서명에 처리 방법을 알 수없는 va_list 인수가 포함되어 있다는 것입니다.

C example from earlier에 표시된대로 va_list argsvfprintf에 직접 전달됩니다. vfprintf manual을 읽는 것은 "va_start 매크로로 초기화되었습니다"라는 일종의 반복 가능한 데이터 구조이고, va_arg을 사용하여 반복 한 후 va_end으로 정리해야한다는 것을 분명히 알 수 있습니다. 그러나 JVM이 손상되지 않도록하는 유일한 방법은 com.sun.jna.Pointer 유형의 args 매개 변수를 만드는 것인데 String[] 또는 Object[]이 더 적합 할 것입니다.

어떻게이 va_list에서 데이터를 가져 옵니까?

N.B. org.gphoto2.jna.GPhoto2Native

추가 :

int gp_log_add_func(int logLevel, LogFunc func, Pointer data); 

org.gphoto2.jna.LogFunc 만든 :

gp_log_add_func에 대한 액세스를 얻기 위해, 나는 약간의 자바 코드를 추가
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의 구현 및 사용 :

,691,363 여기
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); 
+1

해당 플랫폼에서 va_list의 실제 구현을 살펴보아야합니다 (헤더 파일 (vararg.h)로 시작하고 컴파일러 세부 사항을 조사 할 수 있음). va_list는 일반적으로 스택에 대한 포인터이며, 다양한 추출 인수는 포인터를 적절한 크기 오프셋만큼 이동시키는 오프셋 작업입니다. 포인터와 같은 다양한 데이터 추출 방법을 사용하여 포인터를 수동으로 추출해야합니다.getInt (int offset). 액세스하려는 유형에 따라 다릅니다. – technomage

+0

이것은 내가 두려워했던 것입니다. Purist의 관점에서 JNA/Java 비즈니스는 모든 기본 비즈니스와 분리되어야합니다. 이것은 현재 openSuse에서 개발 중이므로 나중에 OS X에서 배포하려고하므로 걱정이됩니다. 불행히도 C/C++에 대해 많이 알지는 못하지만, 아마도 두 번째 네이티브 라이브러리를 사용하여 va_list를 JNA에서 관리하기 쉬운 것으로 변환할까요? – derabbink

+0

JNA가 va_list 처리를위한 매핑을 제공해야한다는 주장은 확실히 논쟁의 여지가 있습니다. 문제를 자유롭게 열어주세요. – technomage

답변

1

(210)는 예는 가변 인자 매크로가 무엇을하고 있는지에 대한 몇 가지 힌트 구현을 가변 인자입니다 :

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는 스택 포인터에 액세스 할 수 없다는 것과 스택 포인터를 제공하기 위해 variadic 콜백을 특별히 처리하기 위해 JNA의 콜백 메커니즘을 네이티브 수준으로 확장해야 할 수도 있습니다.

심지어 잠재적으로 문제가 될 수 있습니다. 위의 예제에서 볼 수 있듯이 variadic 인수에 액세스하려면 실제로 variadic 함수 시그니처의 마지막 명명 된 인수 주소가 필요합니다. 일반적으로 그렇게하는 것은 매우 까다로운 일입니다.

+0

gphoto2 cli를 stdout과 stderr와 일치하는 "영리한 정규 표현식"과 결합하여 되돌릴 것입니다. 그것은 솔루션의 가장 매끄러운되지 않을 수도 있지만 적어도 그것은 더 가능성이 높습니다. – derabbink

+1

@derabbink 참고로 JavaCPP로이 문제를 해결하는 것이 더 쉽습니다. 이미 JNI 라이브러리를 자동으로 빌드, 번들 및로드하는 인프라가 있습니다. 나는 FFmpeg 최근에 그것을해야했다 : https://github.com/bytedeco/javacpp-presets/commit/4ed81465898e0ab27b48f3eb232c26d92ffb69d7 –