Создание объекта параметров C ++ и JNA

Заявление об ограничении ответственности: я почти все игнорирую в C ++, поэтому надеюсь, что не говорю здесь глупостей. Если да, пожалуйста, поправьте меня.

Как разработчик Java, когда я хочу создать новый объект, я использую метод конструктора, который выделит этот объект в памяти и вернет ему дескриптор для меня, и я сохраню этот дескриптор в переменной, я делаю это так .

Foo o = new Foo();

Но в C ++ мне дали понять, что, несмотря на то, что это возможно

Foo createFoo(){
    Foo f;
    f.doSomething();
    return f;
}

// ...

Foo f = createFoo();

Я также могу самостоятельно определить дескриптор, а затем вызвать для него инициализатор, который выделит память и привяжет к нему дескриптор, например:

void initializeFoo(Foo **f){
    f.doSomething();
    return;
}

// ...

Foo f;
initializeFoo(&f);

Итак, мой вопрос: что произойдет, если мы захотим использовать эти методы C ++ в Java с JNA?

Предположим, у меня есть следующий заголовок C ++:

typedef struct Foo f;

Foo createFoo();
void initializeFoo(Foo **f);

Поскольку я понятия не имею, что такое Foo или что содержит структура Foo, я просто собираюсь создать JNA PointerType для объявления моей структуры:

public class Foo extends PointerType{

    public Foo(Pointer address) {
        super(address);
    }
    public Foo() {
        super();
    }
}

Использование метода createFoo также должно быть довольно простым:

public class TestFoo{
    static{
        System.loadLibrary("foolib");
    }

    public static void main(String[] args){
        FooLib lib = (FooLib)Native.loadLibrary("foolib", FooLib.class);

        Foo f = lib.createFoo();
    }

Правильно?

Но у меня вопрос, как я могу использовать функцию initializeFoo ??? Я полагаю, мне нужно было бы создать указатель и передать его функции, но как мне создать указатель, отличный от NULL в JNA? Я пробовал следующий код, но он дает EXCEPTION_ACCESS_VIOLATION.

public class TestFoo{
    static{
        System.loadLibrary("foolib");
    }

    public static void main(String[] args){
        FooLib lib = (FooLib)Native.loadLibrary("foolib", FooLib.class);

        Foo f = new Foo();
        lib.initializeFoo(f); // EXCEPTION_ACCESS_VIOLATION
        lib.initializeFoo(f.getPointer()); // EXCEPTION_ACCESS_VIOLATION
    }

Любая идея?

Спасибо!


person nbarraille    schedule 02.03.2011    source источник
comment
Правильно ли экспортируются ваши функции и методы C ++?   -  person AJG85    schedule 02.03.2011
comment
@ AJG85: Да, они являются частью API.   -  person nbarraille    schedule 02.03.2011


Ответы (2)


Поскольку я понятия не имею, что такое Foo или что содержит структура Foo, я просто собираюсь создать JNA PointerType, чтобы объявить мою структуру.

Это делает невозможным выделение памяти для Foo, так как вы должны знать, сколько памяти вам нужно выделить. Для структур c jna нужен java-класс, отражающий структуру, или, если вы хотя бы знаете его размер, вы можете попробовать использовать класс Memory, у которого ctor принимает аргумент размера.

Для структур и классов C ++, использующих такие функции C ++, как наследование, это не удается, поскольку требуемая память и макет зависят от компилятора и включенных оптимизаций.

person josefx    schedule 02.03.2011
comment
@josefx: Значит, я не могу использовать свой метод intializeFoo(Foo **f) с JNA, если я не знаю структуру Foo? - person nbarraille; 02.03.2011
comment
@josefx: Я бы попытался выделить память для этой структуры, но у меня нет возможности узнать ее размер, он определен в проприетарном API. Я думал, что смогу избежать этой проблемы, определив ее как указатель. - person nbarraille; 02.03.2011
comment
@nathanb, если он определен в проприетарном API, то этот API либо предоставляет метод, возвращающий указатель, либо имеет файл заголовка, определяющий структуру Foo. - person josefx; 02.03.2011
comment
@josefx Нет, API не предоставляет. Он определяет только структуру как непрозрачную: typedef struct sp_session sp_session;, и нет метода, возвращающего процедуру sp_session. Процедура sp_sessions создается с помощью этого метода: SP_LIBEXPORT(sp_error) sp_session_create(const sp_session_config *config, sp_session **sess); - person nbarraille; 02.03.2011
comment
@nathanb, вы можете попробовать com.sun.jna.ptr.PointerByReference для этого и вызвать getValue (), чтобы получить результирующий указатель. - person josefx; 02.03.2011
comment
@josefx Я попробовал сегодня утром, но безуспешно. Как мне это сделать? Должен ли мой класс sp_session расширять его вместо PointerType? - person nbarraille; 02.03.2011
comment
@josefx: Возможно, можно что-то сделать с памятью (Pointer.SIZE): stackoverflow.com/questions/4294264/ - person nbarraille; 02.03.2011
comment
@nathanb вы проверили документацию по jna.java.net, где показаны примеры для PointerByReference. Также вы можете передать одноэлементный массив sp_session с ненулевым значением sp_session, чтобы получить тот же результат. - person josefx; 02.03.2011
comment
@nathanb Не думаю, что это будет работать так, как описано в ссылке. GetPointer (0) не извлекает сохраненное значение указателя, как требует casablanca. - person josefx; 02.03.2011
comment
@josefx Вы правы. Это сработало. Мне пришлось объявить свой метод так: int sp_session_create(Pointer cfg, PointerByReference sess) и назвать его так: 'lib.sp_session_create (cfg.getPointer (), new PointerByReference ()); ` - person nbarraille; 02.03.2011

Foo f;
initializeFoo(&f);

initializeFoo() не «выделяет память и не связывает дескриптор» для f, как вы говорите. Foo f; создает f и размещает его в памяти. initializeFoo() мог бы делать что-то вроде присваивания значений свойствам-членам f и т.п., а также создавать другой объект Foo и назначать его f, но он не делает того, что вы говорите.

С другой стороны,

Foo *f;
f = new Foo();

объявляет указатель Foo. new выделяет память и создает объект Foo, а также назначает ячейку памяти для f (вы можете представить указатель как целое число, содержащее адрес).

Я думаю, вы хотите узнать больше о C ++ и указателях, прежде чем идти дальше.

person Matthew Read    schedule 02.03.2011