1

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

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);
4

1 回答 1

1

先说几个技术点:

  • 由于您的第三个参数引用了第一个参数,因此您不能使用原始数组。因为它显式地保存了本地指针,所以使用 NIO 缓冲区会很尴尬。这给你留下了Memory. 但是,如果您只需要结果String值而不关心指针本身,那么byte[]NIO 缓冲区或Memory将起作用,前提是第三个参数的类型是String[]
  • 您的第三个参数似乎是一个可写的指针数组。您可以使用Pointer[]String[]。您也可以使用Memory,前提是它的分配空间足够大,可以容纳尽可能多的指针值。

然后是更大的问题:

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