JNA实战笔记汇总⼆JNA和CC++的数据类型转换
本⽂接上⼀篇⽂章
⼀、JNA技术的难点
上篇⽂章我们成功实现了Java使⽤JNA调⽤C/C++的函数代码:
int sayHello(){
printf("Hello World!");
return 1;
}
上⾯的代码⾮常简单,在控制台打印输⼊"Hello World",并返回整数型。然后我们在CLibrary中也是定义了⼀个对应的函数
int sayHello();
由于C/C++语⾔和Java语⾔中的int类型对应,所以这⾥并没有复杂的类型转换,也就⼤⼤降低了调⽤JNA和C/C++代码对接的难度。
有过跨语⾔、跨平台开发的程序员都知道,跨平台、语⾔调⽤的难点,就是不同语⾔之间数据类型不⼀致造成的问题。绝⼤部分跨平台调⽤的失败,都是这个问题造成的。关于这⼀点,不论何种语⾔,何种技术⽅案,都⽆法解决这个问题。JNA也不例外。
上⾯说到接⼝中使⽤的函数必须与链接库中的函数原型保持⼀致,这是JNA甚⾄所有跨平台调⽤的难点,因为C/C++的类型与Java的类型是不⼀样的,你必须转换类型让它们保持⼀致,⽐如printf函数在C中的原型为:
void printf(const char *format, [argument]);
你不可能在Java中也这么写,Java中是没有char *指针类型的,因此const char * 转到Java下就是String类型了。
⼆、JNA的常⽤类型映射(Type Mappings)如下:
Native Type Java Type Native Representation
char byte8-bit integer
wchar_t char16/32-bit character
short short16-bit integer
int int32-bit integer
int boolean32-bit integer (customizable)
long, __int64long64-bit integer
long long long64-bit integer
float float32-bit FP
double double64-bit FP
pointer Buffer/Pointer
pointer array[] (array of primitive type)
char*String
wchar_t*WString
char**String[]
wchar_t**WString[]
void*Pointer
void **PointerByReference
int&IntByReference
int&IntByReference
Native Type Java Type Native Representation int*IntByReference
struct Structure
(*fp)()Callback
varies NativeMapped
long NativeLong
pointer PointerType
附带⼀个很重要的API接⼝⽂档地址:
三、具体实例
接下来我们写⼀个复杂⼀点的C++函数
bool checksum(const char* src_data, unsigned short&  check_ret)
然后在Java中调⽤该⽅法,传⼊具体参数,并获取到返回值。
1、⾸先是check.h⽂件和check.cpp⽂件:
check.h
#ifndef TASK_CHECKSUM_H
#define TASK_CHECKSUM_H
typedef signed char int8_t;
typedef short int  int16_t;
typedef int        int32_t;
/* --------------------------------------------------------------------------*/
/**
* @Synopsis          checksum加密算法
*
* @Param src_data    被加密的字符串
*
* @Param check_ret  int16_t类型的加密结果
*
* @Returns          加密是否成功
*/
/* ----------------------------------------------------------------------------*/
extern "C" bool checksum(const char* src_data, unsigned short& check_ret);
#endif
check.cpp
#include "check.h"
#include <string.h>
extern "C"{
bool checksum(const char* src_data, unsigned short&  check_ret) {
bool ret = true;
do {
const int16_t* opt_data = reinterpret_cast<const int16_t*>(src_data);
if (opt_data == NULL || src_data == NULL) {
ret = false;
/*TODO*/
// warn_log();
break;
}
int32_t accu_sum = 0;
int32_t data_len = strlen(src_data);
while (data_len > 1) {
accu_sum += *(opt_data);
opt_data++;
data_len = data_len - 2;
if (accu_sum & 0x80000000) {
accu_sum = (accu_sum >> 16) + (accu_sum & 0xFFFF);
}
}
if (data_len == 1) {
accu_sum += *(reinterpret_cast<const int8_t*>(opt_data));
}
while (accu_sum >> 16) {
accu_sum = (accu_sum >> 16) + (accu_sum & 0xFFFF);
}
check_ret = 0xFFFF & accu_sum;
//        check_ret = (accu_sum == 0xFFFF)?~accu_sum:accu_sum;
//        check_ret = (accu_sum == 0xFFFF)?accu_sum:~accu_sum;
}while(0);
return ret;
}
}
上述代码中checksum函数需要⽤户传⼊⼀个char*指针类型的参数src_data和⼀个short&引⽤类型的check_ret,代码对stc_data进⾏加密操作之后,把加密结果返回到参数check_ret中,函数返回加密是否成功的标记。由于代码中使⽤了string,bool等和C++相关的元素,
所以我们的⽂件后缀⼀定要使⽤.cpp,并且在整个函数外部使⽤了 extern “C” 给C++代码做标记,否则在Java调⽤该⽅法的时候会提⽰⽆法到。
2、然后是CLibrary对象和MainActivity对象
编写完毕代码,使⽤Ndk-build命令⾏进⾏编译,成功⽣成libcheck.so⽂件,配置完毕JNA的相关jar包和库⽂件,把他们添加到已经准备好的jniLibs⽂件夹中,然后创建按⼀个CLibrary类:
//继承Library,⽤于加载库⽂件
public interface Clibrary extends Library {
//加载libhello.so链接库
Clibrary INSTANTCE = (Clibrary) Native.loadLibrary("check", Clibrary.class);
//此⽅法为链接库中的⽅法
//    checksum(const char* src_data, unsigned short&  check_ret)
int checksum(String src_data, IntByReference  check_ret);
}
MainActivity
package;
import AppCompatActivity;
import Bundle;
c++string类型
import Log;
import View;
import Pointer;
import IntByReference;
import PointerByReference;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState){
setContentView(R.layout.activity_main);
}
public void onClick(View view){
IntByReference check_ret =new IntByReference();
int flag = Clibrary.INSTANTCE.checksum("123",check_ret);
Log.d("MainActivity","checksum的返回标记:"+flag);
Log.d("MainActivity","checksum的返回结果:"+Value());
}
}
代码定义了⼀个点击事件,点击按钮调⽤ int flag = Clibrary.INSTANTCE.checksum(“123”,check_ret),并输出checksum的返回标记和加密结果。
项⽬地址:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。