【问题标题】:How to use a struct with a struct in jnr ffi如何在 jnr ffi 中使用带有结构的结构
【发布时间】:2016-07-14 08:25:58
【问题描述】:

我有以下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 代码相同的内容?

【问题讨论】:

  • 为什么不在 Java 代码中也使用int
  • @Shark 因为 int 无法正确编组回本机代码

标签: java c struct ffi jnr


【解决方案1】:

编辑: 我花了更多时间查看代码,我对创建结构的理解略有改变。

我相信你应该声明一个结构的所有内容并使其成为最终的,因为每次你声明一个新成员时,它都会向它所属的结构注册自己。

对于每个用例,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);
    }
}

原件: 我相信正确的方法是使用接受(运行时,结构)的重载 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);
    }
}

【讨论】:

  • 如果有人知道如何声明指向数组的指针,请告诉我。我认为这将是 Struct.arrayOf() 方法和 Address 成员的组合。
  • DataPoint[] points = Struct.arrayOf(runtime, DataPoint.class, 10);指针 data_ptr = Struct.getMemory(points[0]);
【解决方案2】:

分配结构时,如行中

top.second = second;

在您的 Java 代码中,结构从second复制top.second,因此它们成为不同内存区域中的独立实体。稍后,当您在以下行中将 7 分配给 seconda_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 分配了内存。

【讨论】:

  • 感谢您的回答。可悲的是 top.second 是空的,所以我得到了你的建议的运行时异常。我是否需要在上面添加注释或告诉 jnr 为我构建它?
  • @kmp 在设置 a_number 的行之前试试这一行:top.second = new Second(runtime); 我没有使用 jnr-ffi 的经验,只有 C 和 Java 自己使用。
  • 感谢 edwardfanboy,但这样做与我的原始代码没有区别
【解决方案3】:

我已经想通了(顺便说一句,我知道成员应该是私有的并包含在属性中,但我想让代码 sn-p 尽可能小,这不是生产质量代码).. .

如果您将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);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 2020-09-01
    • 2011-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多