概述

我们知道,C语言中的很多数据类型与Java中的数据类型存在很大的区别,那么我们在java中调用C、C++的函数时必然存在一个数据类型的转换,所以弄清楚这些数据类型之间的映射关系对于我们的程序开发有着至关重要的意义,否则很难正确的调用动态类库中的某些功能。

常见普通数据类型的映射转换

C/C++类型

Java 类型

原生表现

bool

boolean

32位(同平台有关,可定制)

char

byte

8位整数

wchart_t

char

平台依赖

short

short

16位整数

int

int

32位整数

long long,_int64

long

64位整数

float

float

32位浮点数

double

double

64位浮点数

pointer

Buffer/Pointer

平台依赖(32位或者64位)

pointer array

[] (基本类型的数组)

32位或64位的指针

JNA常见的数据类型的映射

Java类型

C类型

说明

String

char*

\0结尾的字符数组

WString

wchar_t*

\0结尾的数组(unicode字符串)

String[]

char**

字符串数组

WString[]

wchar_t**

字符串数组(unicode)

Structure

struct*/struct

结构体指针或者结构体

Union

union

联合,等同于结构体

Structure[]

struct[]

结构体数组,临接内存

Callback

(*fp)()

函数指针

NativeMapped

varies

NativeLong

long

长整型

PointerType

pointer

同Pointer

Java模拟C语言的常见数据类型以及实现的示例

一、JNA模拟结构体

C语言中的定义

#pragma pack(push,1)

typedef struct tagValueItem

{

double _dValue;

int _lDate;

int _lTime;

char _exData[6];

}VALUE_ITEM, * PVALUE_ITEM;

#pragma pack(pop)

在java中的模拟

@Structure.FieldOrder({"_dValue", "_lDate", "_lTime", "_exData"})

class VALUE_ITEM extends Structure {

public double _dValue;

public int _lDate;

public int _lTime;

public byte[] _exData = new byte[6];

//内存对齐

public VALUE_ITEM() {

super(ALIGN_NONE);

}

//指针实现

public static class ByReference extends VALUE_ITEM implements Structure.ByReference {

}

//数组实现[]

public static class ByValue extends VALUE_ITEM implements Structure.ByValue{

}

}

代码说明与使用总结

C、C++中的结构体成员默认是public的,无需使用public关键字修饰,而在Java的实现中必须使用public关键字修饰,否则会报成员不存在的错误。

在Java中模拟C、C++的结构体时数据类型的映射必须一一对应,成员属性的名字可以不同(但一般为了方便追踪问题,建议定义成和.h头文件中一致)。

在Java中定义的成员属性的顺序必须和C、C++中头文件结构体中定义的顺序一致,不能调整顺序,否则会引起异常。

必须使用@Structure.FieldOrder或者重载FieldOrder方法,并返回一个字符串数组,数组中的成员是结构体的成员属性列表。

关于内存对齐,如果结构体中使用了内存对齐,那么在java中也必须声明一个无参构

造函数,并调用父类方法指定内存对齐模式,否则有可能引发内存访问异常。

如果需要用到结构体指针,则需要在结构体类的实现中实现静态内部类ByReference,如代码中所示,VALUE_ITEM.ByReference 就等同于 VALUE_ITEM*

如果需要用到结构体对象数组,则需要在结构体类的实现中实现静态内部类ByValue,如上述代码所示, VALUE_ITEM.ByValue 就等同于 VALUE_ITEM[]

二、回调函数Callback以及复杂结构体参数传递

C语言中的定义

typedef struct HISTORY_ITEM

{

int _nDate = 0; //日期 yyyymmdd

int _nTime = 0; //时间 hhmmss

double _dYClose = 0; //前收盘价 分时-均价

double _dOpen = 0; //开

double _dHigh = 0; //高

double _dLow = 0; //低

double _dClose = 0; //收

double _dVol = 0; //成交量

double _dAmount = 0; //成交金额

int _nAdvance = 0; //周期上涨家数. 分笔 B/S

int _nDecline = 0; //周期下跌家数.

//期货

double _dPosition = 0; //持仓

double _dSettle = 0; //结算价

char _exData[32] = { 0 }; //预留数据

} HQCHART_KDATA;

typedef struct tagHQChartKDataResult

{

HQCHART_KDATA* _pData; //K线数据指针

int _lCount; //k线数据数量

wchar_t* _pszName; //股票名称

bool _bResult;

wchar_t* _pszError;

int _lPeriod; //周期

int _lRight; //复权

int _exData[4];

}HQCHART_KDATA_RESULT, * PHQCHART_KDATA_RESULT;

typedef bool(HQ_CALL *pHQChart_LoadKData)(const wchar_t* lpSymbol, long lPeriod, long lRight, HQCHART_KDATA_RESULT* pResult, const wchar_t* pstrGuid);

参数列表说明: lpSymbol,lPeriod,lRight,pstrGuid这几个是输入参数,pResult是输出参数

函数说明: 这是一个函数指针,主要用于加载K线数据.需要在Java中实现取K线数据的逻辑,并使用输出参数pResult传递给C语言的类库中使用。

在java中的模拟

C语言中的回调函数指针在Java中是使用一个集成了StdCallLibrary.StdCallCallback类的接口实现的。

// 结构体模拟实现

@Structure.FieldOrder({"_pData", "_lCount", "_pszName", "_bResult","_lPeriod", "_lRight"})

class HQCHART_KDATA_RESULT extends Structure {

public HQCHART_KDATA.ByReference _pData;

public int _lCount;

public WString _pszName; //股票名称

public int _lPeriod; //周期

public int _lRight; //复权

public HQCHART_KDATA_RESULT() {

super(ALIGN_NONE);

}

public static class ByReference extends HQCHART_KDATA_RESULT implements Structure.ByReference {

public ByReference() {

}

}

}

@Structure.FieldOrder({"tDate", "_nTime", "_dYClose", "_dOpen", "_dHigh",

"_dLow", "_dClose", "_dVol", "_dAmount"})

class HQCHART_KDATA extends Structure {

public int tDate = 0; //日期 yyyymmdd

public int _nTime = 0; //时间 hhmmss

public double _dYClose = 0; //前收盘价 分时-均价

public double _dOpen = 0; //开

public double _dHigh = 0; //高

public double _dLow = 0; //低

public double _dClose = 0; //收

public double _dVol = 0; //成交量

public double _dAmount = 0; //成交金额

public HQCHART_KDATA() {

super(ALIGN_NONE);

}

public static class ByReference extends HQCHART_KDATA implements Structure.ByReference {

public ByReference() {

}

}

}

//回调函数接口定义

interface pHQChart_LoadKData extends StdCallLibrary.StdCallCallback {

boolean invoke(WString lpSymbol,

long lPeriod, long lRight, HQCHART_KDATA_RESULT.ByReference pResult,

WString pstrGuid);

}

//回调函数接口类实现

package com.zealink.hqchart.hqdata;

import com.sun.jna.WString;

public class HQChartLoadKDataImpl implements HQChart.pHQChart_LoadKData {

@Override

public boolean invoke(WString lpSymbol, long lPeriod, long lRight, HQChart.HQCHART_KDATA_RESULT.ByReference pResult, WString pstrGuid) {

System.out.println("pHQChart_LoadKData" + "\t" + lpSymbol + "\t" + lPeriod + "\t" + lRight + "\t" + pstrGuid);

pResult.read();

pResult._lCount = 20;

pResult._lPeriod = (int) lPeriod;

pResult._lRight = (int) lRight;

pResult._pszName = new WString("智慧能源");

//结构体中嵌套结构体指针,指向一个连续的结构体数组并且需要动态申请内存,在此模拟申请20个结构体对象的数组,需要通过如下方式动态申请连续的内存块,否则因为内存不连续而报错。

pResult._pData = new HQChart.HQCHART_KDATA.ByReference();

HQChart.HQCHART_KDATA[] cdata = (HQChart.HQCHART_KDATA[]) pResult._pData.toArray(20);

for (int i = 0; i < pResult._lCount; i++) {

cdata[i].tDate = 20210401 + i;

cdata[i]._nTime = 0;

cdata[i]._dOpen = 13.01 + 0.5 * i;

cdata[i]._dHigh = 14.01 + 0.5 * i;

cdata[i]._dLow = 12.5 + 0.5 * i;

cdata[i]._dClose = 13.05 + 0.5 * i;

if (i >= 1) {

cdata[i]._dYClose = cdata[i - 1]._dClose;

} else {

cdata[i]._dYClose = 13.0;

}

cdata[i]._dVol = 100000000;

cdata[i]._dAmount = 1000000000;

}

//必须调用write方法将数据写入到堆内存中,否则写入的数据都为空。

pResult.write();

return true;

}

}

总结说明

如果结构体中嵌套结构体指针,且指向的是需要动态申请内存的结构体数组,那么该指针需要被定义为public HQCHART_KDATA.ByReference

如果是输入参数的结构体指针,则在函数定义的时候可以定义为public HQCHART_KDATA.ByValue 类型,然后遍历数组取值

动态申请连续的内存时需要通过ByReference(结构体Structure)对象的toArray(数组大小)来申请内存,不能通过Structure[] obj = new Structure[size]这种方式申请,否则办法赋值给ByReference对象。

ByReference对象数据写完后,需要调用write()方法将数据写入到堆内存中,否则数据传递到外层就变成了空数据。

c语言的typedef struct 对应java参数类型,JNA实战系列:02JNA与C语言中的数据类型映射以及复杂结构体传参示例...相关推荐

  1. c语言调用dll实例 结构体传参,Matlab调用Dll,对于自定义结构体数组如何传参? - 程序语言 - 小木虫 - 学术 科研 互动社区...

    %[例子1] % Matlab调用DLL,整形数组传参 v = [1,22,33;44,-56,67]; pv = libpointer('int16Ptr',v); m = get(pv,'Valu ...

  2. c语言调用dll实例 结构体传参,C# 调用Dll 传递字符串指针参(转)

    java -日期处理 1. 计算某年某月份 总有多少个周,每周的开始和结束时间? 思路:1.计算出本月实际的总天数 2.循环每一天,判断这天是否是 周日(1),如果是,周数加1,再次判断是否是月的第一 ...

  3. linux下c语言线程传参数,【linux】C语言多线程中运行线程池,在线程池中运行线程池,,传递的结构体参数值为空/NULL/0...

    C语言多线程中运行线程池,在线程池中运行线程池,,传递的结构体参数值为空/NULL/0 本贴问题,之前已经提问过一次,当时已经解决了,原贴在这里https://segmentfault.com/q/1 ...

  4. Android JNI 第三篇 Java参数类型与本地参数类型对照

    转载请标明出处: http://blog.csdn.net/michael1112/article/details/56665383 江东橘子的博客 这一篇从基础上了解一些Java参数类型与本地参数类 ...

  5. C语言笔记含源码(变量、输入输出、分支、循环、函数、数组、指针、字符串、结构体)小总结

    文章目录 一.变量与输入输出 二.分支语句 三.循环 四.函数 五.数组 六.指针 七.字符串 八.结构体 一.变量与输入输出 定义变量需要:类型.变量名.变量值(可有可无) #include < ...

  6. 【直播回顾】云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第19讲):Java Spring Cloud微服务架构模式与开发实战...

    主讲人:徐雷(云栖社区特邀Java专家) 徐雷,花名:徐雷frank:资深架构师,MongoDB中文社区联席主席,吉林大学计算机学士,上海交通大学硕士.从事了 10年+开发工作,专注于分布式架构,Ja ...

  7. 云栖社区特邀专家徐雷——Java Spring Boot开发实战系列课程【往期直播回顾】...

    徐雷,花名:徐雷frank:资深架构师,MongoDB中文社区联席主席,吉林大学计算机学士,上海交通大学硕士.从事了 10年+开发工作,专注于分布式架构,Java Spring Boot.Spring ...

  8. 【C语言】typedef struct 和 struct 使用区别

    目录 1. 什么是 typedef ? 1.1 typedef为C语言的关键字 1.2 在编程中使用typedef目的 1.3 typedef最简单的应用--为已知数据类型命名 1.3.1  type ...

  9. 【C语言】typedef struct node{}a,*b;到底是什么意思?

      很多小伙伴知道 typedef int a:的作用相当于将int 换名为a: 也知道typedef struct node{xxx}b;的意思是将这个结构体命名为b:但是对于这样的代码 typed ...

  10. c语言无效参数视为严重错误,C语言编译错误:错误:‘-’参数类型无效(有‘int’)...

    一.编译错误代码: #include int main() { #define offsetof(type, member) ((size_t) &((type *)0->member) ...

最新文章

  1. flowlayout java_【简答题】通过使用flowlayout设计出来 java程序如下图所示
  2. 刻意练习:LeetCode实战 -- Task01. 两数之和
  3. putty 配置导出
  4. OpenGL 三角形要点总结
  5. NYOJ 38 布线问题
  6. 微服务网关Gateway中StripPrefix讲解
  7. 数据模型与决策_数据模型与决策复习资料拿走不用客气
  8. 第一行代码 Android (郭霖 著)
  9. druid 数据库连接池,简单配置
  10. Java中构造函数,静态代码块,构造代码块的执行顺序
  11. 数据结构第三章栈和队列(一)
  12. hdu 1233还是畅通工程 最小生成树(入门题)prim算法
  13. Linux命令对应的英文全称
  14. ISODATA聚类分析算法原理与C++实现
  15. 关于软件开发的那些事(三):聊聊软件项目管理及成本核算
  16. Android之音频和视频的提取
  17. 黑马程序员_java语言基础_概述
  18. MySQL索引(一)—— 索引介绍
  19. android+mid播放器,智能播放器动手玩 Android平台之娱乐篇
  20. python单下划线和双下滑线

热门文章

  1. 计算机自动隐藏桌面图标,Windows 8.1 右下角图标莫名自动隐藏
  2. 副高 职称计算机 上海,高级职称评定
  3. python显示实时时间校对_Python实现系统时间自动校正
  4. FireFox精彩电视广告欣赏
  5. TinyKv Project1 Standalone KV
  6. ASP.NET 教程
  7. C2000浮点运算注意事项——CPU和CLA的差异及误差处理技巧
  8. Linux性能优化(七)——网络流量监控工具
  9. 2019年制定的小目标
  10. djyvp计算机电缆参数,DJYVP计算机电缆2x2x1.5型号规格含义