2012-09-26 2 views
1

JNA를 사용하여 java에서 c 함수를 호출합니다. 이 기능은 사용자가 제공하는 메모리에 문자열 목록을 작성하고 서명을 읽 나는 다음과 같은 문제로 실행Java에서 C로 문자열 쓰기 가능 어레이 전달 (JNA 사용)

??llo world! 
H 
? 

Hello world! Hallo Welt! Ciao a tutti! 
0x48 0x65 0x6c 0x6c 0x6f 0x20 0x77 0x6f 0x72 0x6c 0x64 0x21 0x0 0x48 0x61 0x6c 0x6c 0x6f 0x20 0x57 0x65 0x6c 0x74 0x21 0x0 0x43 0x69 0x61 0x6f 0x20 0x61 0x20 0x74 0x75 0x74 0x74 0x69 0x21 0x0 ... 

public interface TestCaseDLL extends Library 
{ 
    int c_getStrings(byte[] buf, int bufSize, Memory strings, IntByReference stringCount); 
} 

public class TestCase 
{ 
    public static void main(String[] args) 
    { 
     byte[] buf = new byte[100]; 
     Memory strings = new Memory(Memory.SIZE * 10); 
     IntByReference stringCount = new IntByReference(10); 

     // c_getStrings() will write the strings continuously to 'buf' and 
     // additionally return a list of starting addresses through the 
     // 'strings' parameter (that is 'strings' point into 'buf'). 
     // 'stringCount' holds the initial array size of 'strings' and will 
     // return the count of returned strings. 
     TestCaseDLL.INSTANCE.c_getStrings(buf, buf.length, strings, stringCount); 

     System.out.println(strings.getPointer(0).getString(0)); 
     System.out.printf("%c\n", buf[0]); // how can this line change 'strings'? 
     System.out.println(strings.getPointer(0).getString(0)); 

     for (byte b: buf) { 
      System.out.print((char) b); 
     } 
     System.out.println(""); 
     for (byte b: buf) { 
      System.out.printf("%#x ", b); 
     } 
     System.out.println(""); 
    } 
} 

출력 : Java 버전과

void c_getStrings(char *buf, size_t bufSize, char *strings[], size_t *stringsCount) 

:

  • 반환 된 st 반지가 부러졌습니다. "Hello World!"가 반환됩니다. "대신 세상에!"
  • 인쇄 buf[0]은 반환 된 문자열을 변경합니다. 나는 단지 그 가치를 읽으므로 여기에서 어떤 일이 일어나고 있는지 단서를 봤습니다.

내 형식 매핑이 손상되었거나 기본 사항이 누락 되었습니까?

업데이트

내가 지금 사용 사용

void c_getStrings(Memory buf, int bufSize, String[] strings, IntByReference stringCount); 

나는 그것을 다시 할 경우에, 나는 두 가지 기능으로 분할 할 technomage에 의해 제안 :

void c_fill(char *buf, size_t bufSize); 
void c_parseToStringArray(const char *buf, const char *strings[], size_t stringsSize); 
+0

정말 대단한 API입니다. – technomage

+0

@technomage 문자열 목록을 반환하는 데 사용하는 C API는 무엇입니까? –

+0

현재'c_getString'은 메모리를 할당하지 않습니다 (좋은 생각입니다).버퍼'buf '만 반환해도 충분하지만 문자열 배열'strings'을 사용하면 함수를 간단하게 사용할 수 있습니다. 동의하지 않니? –

답변

1

먼저 몇 가지 기술 점수 :

  • 세 번째 인수가 첫 번째 인수를 참조하기 때문에 원시 배열을 사용할 수 없습니다. 네이티브 포인터를 명시 적으로 저장하기 때문에 NIO 버퍼를 사용하는 것은 어색합니다. 그러면 Memory이됩니다. 그러나 결과적으로 String 값이 필요하고 포인터 자체는 신경 쓰지 않는다면 byte[], NIO 버퍼 또는 Memory이 작동합니다. 세 번째 인수는 String[]이어야합니다.
  • 세 번째 인수는 쓰기 가능한 포인터 배열로 나타납니다. Pointer[] 또는 String[]을 사용할 수 있습니다. 또한 Memory을 사용할 수 있습니다. 단, 제공된만큼의 포인터 값을 보유 할만큼 충분히 큰 것이어야합니다.

그런 다음 큰 질문 :

  • 왜 당신이 그 버퍼에 (아마도 임베디드 NUL 문자로) 버퍼와 개별 포인터 모두 필요합니까?
  • JNA에서 매핑 할 때 JNA가 자체 문자열 할당을 수행하기 때문에 바보처럼 보입니다. 메모리 버퍼를 풀링 된 문자열 저장소로 제공하는 경우 String[] 세 번째 인수에서 문자열을 얻은 후에는 필요하지 않습니다. 버퍼의 내용을 조작하려는 경우 이러한 변경 사항은 "반환 된"문자열에 반영되지 않습니다.
+0

'int c_getStrings (byte [] buf, int bufSize, String [] strings, IntByReference stringCount);로 변경하면 약간의 성공이있었습니다. ... 문자열 [] 문자열 = 새 문자열 [10]; 결과는 '?? 세계 LLO!'여전히 ' 하지만 읽기' –

+0

[0]'더 이상 부패'strings'하지 버피 나는 단지 관리; TestCaseDLL.INSTANCE.c_getStrings (BUF, 일까 buf.length, 문자열, stringCount) 문자열 배열에 대해. 버퍼가 있으므로'c_getStrings'는 메모리를 할당 할 필요가 없습니다. (이후에 버퍼를 조정하려고하지는 않는다.) –

+0

'byte []'을 사용할 수 없으므로'Memory' 나 NIO 버퍼를 사용해야한다. 함수 내에서 참조되는'byte []'에 대한 네이티브 메모리는 네이티브 호출의 지속 기간 동안 만 유효하며 반환 된 포인터 배열로부터의'String []'변환은 이후에 발생합니다. – technomage