如何在 jnr ffi 中使用带有结构的结构
How to use a struct with a struct in jnr ffi
我有以下c代码:
#include <stdio.h>
struct Second {
int a_number;
};
struct Top {
struct Second second;
};
void lets_go(struct Top *top) {
printf("The number is %d\n", top->second.a_number);
}
我想从 Java:
int main(void) {
struct Top top = {{8}};
lets_go(&top);
}
我也想使用 jnr-ffi,所以我查看了测试结果:
package structs.playing;
import structs.playing.Program.Test.Top;
import structs.playing.Program.Test.Second;
import jnr.ffi.LibraryLoader;
import jnr.ffi.Runtime;
import jnr.ffi.Struct;
public final class Program {
public static interface Test {
void lets_go(Top top);
public static final class Second extends Struct {
public final Signed32 a_number = new Signed32();
public Second(final Runtime runtime) {
super(runtime);
}
}
public static final class Top extends Struct {
public Second second;
public Top(final Runtime runtime) {
super(runtime);
}
}
}
public static void main(final String[] args) {
Test test = LibraryLoader.create(Test.class).load("test");
Runtime runtime = Runtime.getRuntime(test);
Top top = new Top(runtime);
Second second = new Second(runtime);
top.second = second;
second.a_number.set(7);
test.lets_go(top);
}
}
问题是 a_number
的值根本没有设置,所以我在输出中得到了一个垃圾值,例如:
The number is 46645760
那么如何获得与我的 C 代码相同的值?
分配结构时,如行
top.second = second;
在您的 Java 代码中,该结构从 second
复制 到 top.second
,因此它们成为不同区域的独立实体的记忆。稍后,当您在以下行中将 7 分配给 second
的 a_number
属性 时:
second.a_number.set(7);
top.second
对应的属性保持不变,因为它们不是同一个对象
为了得到与您的 C 代码相同的结果,请尝试将您的 main
方法更改为:
public static void main(final String[] args) {
Test test = LibraryLoader.create(Test.class).load("test");
Runtime runtime = Runtime.getRuntime(test);
Top top = new Top(runtime);
top.second.a_number.set(8);
test.lets_go(top);
}
不需要初始化新的 Second
对象,因为在初始化 Top
对象的过程中已经为 top.second
分配了内存。
我已经弄明白了(顺便说一句,我知道成员应该是私有的并包装在属性中,但我想让代码片段尽可能小,这不是生产质量代码)。 .
如果将 Pointer 成员变量放入结构中,则可以在构造子结构时使用它的内存,如下所示...
package structs.playing;
import structs.playing.Program.Test.Top;
import jnr.ffi.LibraryLoader;
import jnr.ffi.Runtime;
import jnr.ffi.Struct;
public final class Program {
public static interface Test {
void lets_go(Top top);
public static final class Second extends Struct {
public final Signed32 a_number = new Signed32();
public Second(final Runtime runtime) {
super(runtime);
}
}
public static final class Top extends Struct {
private final Pointer secondPointer = new Pointer();
public final Second second;
public Top(final Runtime runtime) {
super(runtime);
second = new Second(runtime);
second.useMemory(secondPointer.getMemory());
}
}
}
public static void main(final String[] args) {
Test test = LibraryLoader.create(Test.class).load("test");
Runtime runtime = Runtime.getRuntime(test);
Top top = new Top(runtime);
top.second.a_number.set(8);
test.lets_go(top);
}
}
编辑:
我花了更多时间查看代码,我对创建结构的理解略有改变。
我认为您应该声明有关结构的所有内容并将其设为最终结构,因为每次您声明一个新成员时,它都会向它所属的结构注册自己。
struct 中有一些适用于每个用例的辅助函数。重载的 array() 方法允许您注册一个成员数组或结构数组。 inner() 方法允许您注册单个结构。否则,您只需定义新的 Member 对象,它们就会自动注册。
例如:
struct Second {
int a_number;
};
struct Top {
struct Second second;
struct Second seconds[5];
int another_number;
int more_numbers[5];
};
表示为:
public final class Second extends Struct {
public final Signed32 a_number = new Signed32();
public Second(final Runtime runtime) {
super(runtime);
}
}
public final class Top extends Struct {
public final Second second = inner(new Second(getRuntime()));
public final Second[] seconds = array(new Second[5]);
public final Signed32 another_number = new Signed32();
public final Signed32[] more_numbers = array(new Signed32[5]);
public Top(final Runtime runtime) {
super(runtime);
}
}
原文:
我相信执行此操作的正确方法是使用接受 (Runtime, Struct) 的重载 Struct 构造函数。
https://github.com/jnr/jnr-ffi/blob/master/src/main/java/jnr/ffi/Struct.java#L129
protected Struct(Runtime runtime, Struct enclosing) {
this(runtime);
__info.alignment = enclosing.__info.alignment;
}
此构造函数强制封闭结构共享其内存。所以在你的例子中我认为它看起来像这样:
package structs.playing;
import structs.playing.Program.Test.Top;
import structs.playing.Program.Test.Second;
import jnr.ffi.LibraryLoader;
import jnr.ffi.Runtime;
import jnr.ffi.Struct;
public final class Program {
public static interface Test {
void lets_go(Top top);
public static final class Second extends Struct {
public final Signed32 a_number = new Signed32();
public Second(final Runtime runtime, final Struct enclosing) {
super(runtime, enclosing);
}
}
public static final class Top extends Struct {
public Second second;
public Top(final Runtime runtime) {
super(runtime);
}
}
}
public static void main(final String[] args) {
Test test = LibraryLoader.create(Test.class).load("test");
Runtime runtime = Runtime.getRuntime(test);
Top top = new Top(runtime);
Second second = new Second(runtime, top);
top.second = second;
second.a_number.set(7);
test.lets_go(top);
}
}
请注意对 Second 构造函数的更改,并注意我将 Top 对象传递给了 Second 对象,因此它知道 top 正在封闭它。这没有经过测试,只是分享我在尝试理解代码时发现的内容。
我认为您的示例中发生的情况是,第二个对象正在分配其自己的内存,而 Top 对此一无所知。
如果这不起作用,我会建议考虑做这样的事情:
public static final class Top extends Struct {
public Second second = new Second(getRuntime(), this);
public Top(final Runtime runtime) {
super(runtime);
}
}
我有以下c代码:
#include <stdio.h>
struct Second {
int a_number;
};
struct Top {
struct Second second;
};
void lets_go(struct Top *top) {
printf("The number is %d\n", top->second.a_number);
}
我想从 Java:
int main(void) {
struct Top top = {{8}};
lets_go(&top);
}
我也想使用 jnr-ffi,所以我查看了测试结果:
package structs.playing;
import structs.playing.Program.Test.Top;
import structs.playing.Program.Test.Second;
import jnr.ffi.LibraryLoader;
import jnr.ffi.Runtime;
import jnr.ffi.Struct;
public final class Program {
public static interface Test {
void lets_go(Top top);
public static final class Second extends Struct {
public final Signed32 a_number = new Signed32();
public Second(final Runtime runtime) {
super(runtime);
}
}
public static final class Top extends Struct {
public Second second;
public Top(final Runtime runtime) {
super(runtime);
}
}
}
public static void main(final String[] args) {
Test test = LibraryLoader.create(Test.class).load("test");
Runtime runtime = Runtime.getRuntime(test);
Top top = new Top(runtime);
Second second = new Second(runtime);
top.second = second;
second.a_number.set(7);
test.lets_go(top);
}
}
问题是 a_number
的值根本没有设置,所以我在输出中得到了一个垃圾值,例如:
The number is 46645760
那么如何获得与我的 C 代码相同的值?
分配结构时,如行
top.second = second;
在您的 Java 代码中,该结构从 second
复制 到 top.second
,因此它们成为不同区域的独立实体的记忆。稍后,当您在以下行中将 7 分配给 second
的 a_number
属性 时:
second.a_number.set(7);
top.second
对应的属性保持不变,因为它们不是同一个对象
为了得到与您的 C 代码相同的结果,请尝试将您的 main
方法更改为:
public static void main(final String[] args) {
Test test = LibraryLoader.create(Test.class).load("test");
Runtime runtime = Runtime.getRuntime(test);
Top top = new Top(runtime);
top.second.a_number.set(8);
test.lets_go(top);
}
不需要初始化新的 Second
对象,因为在初始化 Top
对象的过程中已经为 top.second
分配了内存。
我已经弄明白了(顺便说一句,我知道成员应该是私有的并包装在属性中,但我想让代码片段尽可能小,这不是生产质量代码)。 .
如果将 Pointer 成员变量放入结构中,则可以在构造子结构时使用它的内存,如下所示...
package structs.playing;
import structs.playing.Program.Test.Top;
import jnr.ffi.LibraryLoader;
import jnr.ffi.Runtime;
import jnr.ffi.Struct;
public final class Program {
public static interface Test {
void lets_go(Top top);
public static final class Second extends Struct {
public final Signed32 a_number = new Signed32();
public Second(final Runtime runtime) {
super(runtime);
}
}
public static final class Top extends Struct {
private final Pointer secondPointer = new Pointer();
public final Second second;
public Top(final Runtime runtime) {
super(runtime);
second = new Second(runtime);
second.useMemory(secondPointer.getMemory());
}
}
}
public static void main(final String[] args) {
Test test = LibraryLoader.create(Test.class).load("test");
Runtime runtime = Runtime.getRuntime(test);
Top top = new Top(runtime);
top.second.a_number.set(8);
test.lets_go(top);
}
}
编辑: 我花了更多时间查看代码,我对创建结构的理解略有改变。
我认为您应该声明有关结构的所有内容并将其设为最终结构,因为每次您声明一个新成员时,它都会向它所属的结构注册自己。
struct 中有一些适用于每个用例的辅助函数。重载的 array() 方法允许您注册一个成员数组或结构数组。 inner() 方法允许您注册单个结构。否则,您只需定义新的 Member 对象,它们就会自动注册。
例如:
struct Second {
int a_number;
};
struct Top {
struct Second second;
struct Second seconds[5];
int another_number;
int more_numbers[5];
};
表示为:
public final class Second extends Struct {
public final Signed32 a_number = new Signed32();
public Second(final Runtime runtime) {
super(runtime);
}
}
public final class Top extends Struct {
public final Second second = inner(new Second(getRuntime()));
public final Second[] seconds = array(new Second[5]);
public final Signed32 another_number = new Signed32();
public final Signed32[] more_numbers = array(new Signed32[5]);
public Top(final Runtime runtime) {
super(runtime);
}
}
原文: 我相信执行此操作的正确方法是使用接受 (Runtime, Struct) 的重载 Struct 构造函数。 https://github.com/jnr/jnr-ffi/blob/master/src/main/java/jnr/ffi/Struct.java#L129
protected Struct(Runtime runtime, Struct enclosing) {
this(runtime);
__info.alignment = enclosing.__info.alignment;
}
此构造函数强制封闭结构共享其内存。所以在你的例子中我认为它看起来像这样:
package structs.playing;
import structs.playing.Program.Test.Top;
import structs.playing.Program.Test.Second;
import jnr.ffi.LibraryLoader;
import jnr.ffi.Runtime;
import jnr.ffi.Struct;
public final class Program {
public static interface Test {
void lets_go(Top top);
public static final class Second extends Struct {
public final Signed32 a_number = new Signed32();
public Second(final Runtime runtime, final Struct enclosing) {
super(runtime, enclosing);
}
}
public static final class Top extends Struct {
public Second second;
public Top(final Runtime runtime) {
super(runtime);
}
}
}
public static void main(final String[] args) {
Test test = LibraryLoader.create(Test.class).load("test");
Runtime runtime = Runtime.getRuntime(test);
Top top = new Top(runtime);
Second second = new Second(runtime, top);
top.second = second;
second.a_number.set(7);
test.lets_go(top);
}
}
请注意对 Second 构造函数的更改,并注意我将 Top 对象传递给了 Second 对象,因此它知道 top 正在封闭它。这没有经过测试,只是分享我在尝试理解代码时发现的内容。
我认为您的示例中发生的情况是,第二个对象正在分配其自己的内存,而 Top 对此一无所知。
如果这不起作用,我会建议考虑做这样的事情:
public static final class Top extends Struct {
public Second second = new Second(getRuntime(), this);
public Top(final Runtime runtime) {
super(runtime);
}
}