我使用 JNA 在 Java 代码中使用了 C 库。我有这些 C 结构,我需要用 Java 打印其成员。由于内存对齐和填充,大小与我实际预期的不同。因此,我使用了编译指示包,这就是现在结构的样子。
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )
PACK(
typedef struct
{
size_t size;
uint8_t bytes[48];
} ipj_tid_t);
PACK(
typedef struct
{
bool has_epc; //1
ipj_epc_t epc; //64+8
bool has_tid; //1
ipj_tid_t tid; //48+8
bool has_pc; //1
uint32_t pc; //4
bool has_xpc; //1
uint32_t xpc; //4
bool has_crc; //1
uint32_t crc; //4
bool has_timestamp; //1
uint64_t timestamp; //8
bool has_rssi; //1
int32_t rssi; //4
bool has_phase; //1
int32_t phase; //4
bool has_channel; //1
uint32_t channel; //4
bool has_antenna; //1
uint32_t antenna; //4
} ipj_tag); //total size= 174
PACK(
typedef struct
{
bool has_error;
ipj_error error;
bool has_test_id;
uint32_t test_id;
bool has_result_1;
uint32_t result_1;
bool has_result_2;
uint32_t result_2;
bool has_result_3;
uint32_t result_3;
size_t data_count;
uint32_t data[16];
bool has_timestamp;
uint64_t timestamp;
size_t lt_buffer_count;
uint32_t lt_buffer[21];
} ipj_test_report);
PACK(
typedef struct
{
size_t size;
uint8_t bytes[64];
} ipj_tag_operation_data_t);
PACK(
typedef struct
{
bool has_error; //1
ipj_error error; //4
bool has_tag; //1
ipj_tag tag; //174
bool has_tag_operation_type; //1
ipj_tag_operation_type tag_operation_type; //4
bool has_tag_operation_data; //1
ipj_tag_operation_data_t tag_operation_data; //72
bool has_retries; //1
uint32_t retries; //4
bool has_diagnostic; //1
uint32_t diagnostic; //4
bool has_timestamp; //1
uint64_t timestamp; //8
size_t lt_buffer_count; //8
uint32_t lt_buffer[30]; //120
} ipj_tag_operation_report); //405
当我从Visual Studio运行代码时,我没有收到任何错误,异常或崩溃。但是当我从Java调用它时,jvm正在崩溃。为什么会这样?C 代码中还有其他未打包的结构。会不会是原因?请指教。
我上面显示的结构在 C 中使用。从 C 代码返回的是所有处理后的这个结构。
#define RX_MAX_SIZE 405
#pragma pack(push, 1)
typedef struct _report
{
ipj_report_id report_id;
uint32_t data_size;
uint32_t data[RX_MAX_SIZE];
} report;
#pragma pack(pop)
已使用的等效 JNA 结构如下所示。
public class _report extends Structure {
public static class ByValue extends _report implements Structure.ByValue {
}
public _report() {
super();
setAlignType(ALIGN_NONE);
}
public _ipj_report_id reportid;
public int data_size;
public int[] data = new int[405];
@Override
protected List getFieldOrder() {
return Arrays.asList("reportid", "data_size", "data");
}
}
public class _ipj_report_id extends Structure {
public int ipj_report_id;
public _ipj_report_id() {
super();
setAlignType(ALIGN_NONE);
}
@Override
protected List getFieldOrder() {
return Arrays.asList("ipj_report_id");
}
}
下面是我在调试 JNA 代码时得到的结构。
_report$ByValue(auto-allocated@0x18918cc0 (1628 bytes)) {
_ipj_report_id reportid@0=_ipj_report_id(allocated@0x18918cc0 (4 bytes) (shared from auto-allocated@0x18918cc0 (1628 bytes))) {
int ipj_report_id@0=0
}
int data_size@4=195
int data[405]@8=[I@78bb0ecb
}
以下是我在 JNA 中调用此方法的方式。
rfidlib rlib = (rfidlib) Native.loadLibrary("rfidlib", rfidlib.class);
_report.ByValue report = new _report.ByValue();
report = rlib.get_next_reports();
JNA 假定当前目标平台(在本例中为 MS 编译器)的默认结构布局。
您可以通过在使用 -Djna.dump_memory=true
调用 JVM 后调用 Structure.toString()
来打印 JNA 生成的内存布局的布局。
然后,您可以将所需的结构布局与 JNA 生成的实际布局进行比较,以查找差异。 如果你在 Java 结构中一般使用 boolean
,默认是分配一个原生int
,所以如果它的大小与你的原生bool
不同,你需要在 Java 端使用 byte
或显式提供TypeMapper
到你的Structure
,以指示boolean
应该转换为与原生bool
兼容的大小(注意本机的大小bool
不是由 C 标准定义的)。
我建议不要在代码中使用#pragma pack
,除非您明确需要它。
请使用 Java Structure
实现及其调试输出更新您的问题。