Есть ли конкретный способ работать с постоянными членами указателя структуры в JNA?

#java #struct #mapping #jna

#java #структура #отображение #jna

Вопрос:

У меня есть следующая структура C:

 typedef struct {
    void           *instance;
    const info_st  *info;
} core_st;
  

Который я сопоставляю со следующим классом Java с помощью JNA:

 public class core_st extends Structure {

    public Pointer instance;
    public info_st.ByReference info;

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("instance", "info");
    }
}
  

У меня также есть следующая функция, взятая из библиотеки dll:

 uint32_t open_core(uint32_t core_id, core_st **core);
  

И относительное отображение JNA:

 int open_core(int core_id, core_st[] core);
  

Наконец, я написал Java-программу, которая вызывает функцию таким образом:

 core_st[] cores = new core_st[1];
MyLibrary.INSTANCE.open_core(0, cores);
  

Функция должна заполнить cores[0] элементы результатом операции «открыть». В частности, два поля являются двумя указателями на что-то другое. Что происходит, так это то, что void *instance поле всегда заполняется правильно, но info поле всегда равно null (указатель на ноль).
Если я установлю для параметра jna.memory_dump значение true , любой вызов core_st.toString() возвращает всегда один и тот же результат:

 memory dump
[70cb64e7]
[fd7f0000]
[00000000]
[00000000]
  

Похоже, что указатель на структуру info отсутствует в памяти, считываемой JNA. Тот же вызов, выполняемый аналогичной программой на C, работает нормально, оба указателя заполнены правильно.
Я также попытался изменить отображение core_st, просто для целей тестирования:

 public class core_st extends Structure {

    public long instance;
    public long info;

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("instance", "info");
    }
}
  

Но я не получил различий в результате. экземпляр получает ненулевое значение, а информация всегда равна нулю. Я работаю с 64-разрядной виртуальной машиной.
Мне было интересно, может ли проблема заключаться в модификаторе const поля info? Может ли модификатор const в поле структуры типа pointer изменить способ хранения структуры в памяти?

Ответ №1:

Может const модификатор в поле struct типа pointer изменить способ хранения структуры в памяти?

Ответ, возможно, зависит от компилятора. Более важным для вашего вопроса является то, как const влияет на способ доступа к полю на собственной стороне. Независимо от того, что вы делаете на стороне Java, после инициализации info поля вашей core_st структуры вы не сможете его изменить.

И именно поэтому вы видите то, что видите здесь: определяя, public info_st.ByReference info; вы инициализируете core_st структуру указателем на NULL и получаете адрес памяти, 0x0 сохраненный для этого поля. При доступе к этому полю с помощью API вы не можете изменить адрес памяти, он зависает.

Вы видите те же результаты, инициализируя его как long со значением по умолчанию (0).

Решение зависит от того, как API заполняет это значение. Если на собственной стороне open_core функция предполагает, что info поле уже инициализировано указателем на выделенную структуру, и просто изменяет значения в указанной памяти, все готово. Вам просто нужно инициализировать это поле при первом создании экземпляра структуры.

Вы ничего не говорите мне о том, на что *info указывает, поэтому ответ отличается в зависимости от того, является ли это массивом info_st структур или одной структурой. Если это единая структура, у вас есть:

 public class core_st extends Structure {

    public Pointer instance;
    public info_st.ByReference info = new info_st.ByReference();

}
  

Это выделит соответствующие память для info_st структуры и хранить только для чтения, указатель в вашей core_st структуре. В зависимости от внутренней работы open_core() (и на основе вашего отчета, что это, похоже, работает на стороне C), это может сработать!

Если нет, возможно, публикация рабочего кода C помогла бы определить, существует ли другое сопоставление JNA, которое помогло бы, или вам придется обойти это с помощью вашей собственной функции-оболочки dll.