将字符串可写数组从Java传递到C(使用JNA)

时间:2012-09-26 13:55:13

标签: java c jna

我使用JNA从java调用c函数。该函数将字符串列表写入用户提供的内存,其签名为:

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

使用Java版本:

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("");
    }
}

输出

??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 ...

我遇到了以下问题:

  • 返回的字符串已损坏。它应该返回“Hello World!”而不是“?? llo 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);

1 个答案:

答案 0 :(得分:1)

前几个技术要点:

  • 由于您的第三个参数引用了第一个参数,因此您无法使用原始数组。由于它显式保存了本机指针,因此使用NIO缓冲区会很尴尬。这会让你Memory。但是,如果您只需要生成的String值并且不关心指针本身,那么byte[],NIO缓冲区或Memory将起作用,前提是第三个参数是输入String[]
  • 您的第三个参数似乎是一个可写的指针数组。您可以使用Pointer[]String[]。你也可以使用Memory,只要它被分配得足够大,可以保存尽可能多的指针值。

然后是更大的问题:

  • 为什么你需要一个缓冲区(可能是嵌入式NUL字符)和指向该缓冲区的单个指针?
  • 从JNA映射时,这看起来很愚蠢,因为JNA自己进行字符串分配。如果您只是将内存缓冲区作为池化字符串存储提供,则从String[]第三个参数获取字符串后就不需要它了。如果您打算在缓冲区中操作内容,则此类更改不会反映在“返回”字符串中。