JNA 如何将 String[] 从 Java 传递给 C 代码

JNA how to pass String[] from Java to C code

我有一个问题。我首先需要了解如何传递 'String[] contentsStatic'。我可以在 JNA 文档中看到 String[] 应该映射到 Char**。我不确定如何将其映射到 Java 端。在我的特定实现中,我什至不确定这是否真的有效,因为我尝试使用的 C 代码是 MatLab,因此在 C 代码中它期望一个 'const emxArray_char_T *contentsStatic。我不知道这是什么。

这是C端:

Initialise(const emxArray_char_T *contentsStatic, const
                    emxArray_char_T *contentsDynamic, int b_phoneAngleDeg, double
                            b_stepCalibrationOffset, int b_initialFloorNumber, int
                            b_initialPointingAngleDeg, int b_initialAlignmentMode, bool *mapStatus, bool
  *paramStatus);

Java 边是:

initialise(String[] contentsStatic,
                                String[] contentsDynamic,
                                int phoneRelativeToBodyDegree,
                                double initialStepCalibrationOffset, 
                                int startingFloorID,
                                LatLng startingLatLong,
                                double startingAccuracy,
                                boolean _CDontActuallyUse,
                                int phoneOrientation,
                                int phoneOrientationUse,
                                boolean magntometerValid
                                )

作图方法供参考:

private struct MatWrap
{
    var MatString: MatString
    private var string_size_array_to_pass: [Int32]
    private var string_bytes_int8: [Int8]

    init(string: String)
    {
        let string_size = MatWrap.getSize(string: string)

        self.string_bytes_int8 = MatWrap.getInt8Array(string: string)
        self.string_size_array_to_pass = MatWrap.getSizeArray(size: string_size)

        self.MatString = MatWrap.makeMatString(
            data: &self.string_bytes_int8,
            size: &self.string_size_array_to_pass,
            allocatedSize: string_size
        )
    }

    private static func getInt8Array(string: String) -> [Int8] {
        let data = string.data(using: .ascii, allowLossyConversion: false)!
        let bytes = [UInt8](data)
        let bytes_int8 = bytes.map{Int8([=13=])}
        return bytes_int8
    }

    private static func getSize(string: String) -> Int32 {
        return Int32(string.lengthOfBytes(using: .ascii))
    }

    private static func getSizeArray(size: Int32) -> [Int32] {
        return [1, size]
    }

    private static func makeMatString(data: UnsafeMutablePointer<Int8>, size: UnsafeMutablePointer<Int32>, allocatedSize: Int32) -> MatString {
        return MatString(data: data, size: size, allocatedSize: allocatedSize, numDimensions: 1, canFreeData: false)
    }
}

用于准备要传递的连接 String[] 的方法:

allFloorsDynamic_wrappedMatString =  MatWrap(string: contentsDynamic.joined())

您在询问如何传递 String[] 但这不是本机函数所期望的。

the Matlab docsemxArray_char_T是一个结构:

struct emxArray_char_T
{
   char * str;
   int size;
};

进一步,阅读文档,你可以看到API的描述:

The code generator produces C/C++ array definitions that depend on the array element type and whether the array uses static or dynamic memory allocation. The two kinds of memory allocation for an array require two different implementations:

  • For an array whose size is bounded within a predefined threshold, the generated C/C++ definition consists of a pointer to memory and an integer that stores the total number of array elements, the array size. The memory for this array comes from the program stack and is statically allocated.

  • For an array whose size is unknown and unbounded at compile time, or whose bound exceeds a predefined threshold, the generated C/C++ definition consists of a data structure called an emxArray. When an emxArray is created, intermediate storage bounds are set based on the current array size. During program execution, as intermediate storage bounds are exceeded, the generated code appropriates additional memory space from the heap and adds it to the emxArray storage. The memory for this array is dynamically allocated.

对于将 const 值传递给本机端的情况,您可以使用静态分配的版本。但是,在这里你 运行 进入了 JNA 的一个限制:当你定义结构时,数组的大小必须是已知的。所以要使用一个结构,你必须这样做:

@FieldOrder ({"str", "size"})
class emxArray_char_T_3 extends Structure {
    public String[] strArray = new String[3];
    public int size = 3;
}

您可以定义它,然后设置 3 个 strArray 元素。你可以为不同的大小做一个类似的数组。

不过,MATLAB 似乎有创建这个数组的辅助函数,例如 emxCreateWrapper_char_T。您可能想弄清楚如何使用它们。

进一步深入研究文档,they say:

If you are not using dynamic memory allocation, arrays in structures translate into single-dimension arrays, not pointers.

这对字符串来说是一个挑战,字符串是可变长度数组,而其他语言的典型 String[] 映射将是指向其他地方的字符串的指针数组。这意味着要直接使用具有 const 类型的现有结构,您必须为字符串定义定长字符数组。

查看您在编辑中添加的字符串数组的语法,看起来您仍然必须传递单个字符串,但符号 joined 暗示它需要某种分隔符符号。同样,您必须搜索 API 才能准确找到分隔符!