Java与C连动时的数据类型分析

来源:http://blog.csdn.net/flxyzsby/article/details/597588




. JavaC连动时的数据类型分析
        刚才我们只是举了一个简单的例子来说明连动的基本方法
我们在编写真正实用的程序的时候 , 我们必然需要传递参数 .Java  C 数据类型的对应关系是这样的
 
-----------------------------------------------------------------------------------------------------------------------
Java 数据类型                      C 数据类型                     字节数
-----------------------------------------------------------------------------------------------------------------------
boolean                        jboolean                       1
byte                      jbyte                            1
char                            jchar                           2
short                           jshort                          2
int                        jint                       4
long                      jlong                            8
float                      jfloat                            4
double                          jdouble                         8
-----------------------------------------------------------------------------------------------------------------------
 
Java 所有的数组都拥有相应的 C 数组类型
 
-----------------------------------------------------------------------------------------------------------------------
Java 数据类型                      C 数据类型                          
-----------------------------------------------------------------------------------------------------------------------
Boolean[]                                      jbooleanArray                               
byte[]                                     jbyteArray                                     
char[]                                    jcharArray                                    
short[]                                   jshortArray                                   
int[]                              jintArray                                       
long[]                                     jlongArray                                     
float[]                                    jfloatArray                                    
double[]                                 jdoubleArray                                 
object[]                                  jobjectArra y                         
-----------------------------------------------------------------------------------------------------------------------
还有一个类型 jarray, 它是一个通用数组
jini.h 可以看出
C , 所以的数组数据类型都是 jobject 的同义类型 , 但是在 C++ 中是有继承关系的 .
继承关系为
Jobject <  ――  jarray <  ―― jobjectArra y,  jbooleanArray, jbyteArray, jcharArray, jshortArray, jintArray, jlongArray, jfloatArray, jdoubleArray
 
对这些数组类型的操作函数典型的有
jsize (JNICALL *GetArrayLength)
      (JNIEnv *env, jarray array);
获得数组的长度 , 适用于所有类型
你可以这样使用
C
jsize length = (*env)->GetArrayLength(env,array);
C++
Jsize length = env->GetArrayLength(array);
C C++ 中使用略有区别 , 请大家使用注意以下 , 下面提到的函数也是如此 .
 
 
在标题文件 jni.h , 这些数据类型用 typedef 语句声明为目标平台上的等价数据类型 .
还有这两个常量  JNI_FALSE = 0 JNI_TRUE = 1.
 
jboolean * (JNICALL *GetBooleanArrayElements)
      (JNIEnv *env, jbooleanArray array, jboolean *isCopy);
    jbyte * (JNICALL *GetByteArrayElements)
      (JNIEnv *env, jbyteArray array, jboolean *isCopy);
    jchar * (JNICALL *GetCharArrayElements)
      (JNIEnv *env, jcharArray array, jboolean *isCopy);
    jshort * (JNICALL *GetShortArrayElements)
      (JNIEnv *env, jshortArray array, jboolean *isCopy);
    jint * (JNICALL *GetIntArrayElements)
      (JNIEnv *env, jintArray array, jboolean *isCopy);
    jlong * (JNICALL *GetLongArrayElements)
      (JNIEnv *env, jlongArray array, jboolean *isCopy);
    jfloat * (JNICALL *GetFloatArrayElements)
      (JNIEnv *env, jfloatArray array, jboolean *isCopy);
    jdouble * (JNICALL *GetDoubleArrayElements)
      (JNIEnv *env, jdoubleArray array, jboolean *isCopy);
这些函数获得数组的内容 , 返回数组指针 , i sCopy  如果进行拷贝,指向以 JNI_TRUE 填充的 jboolean, 否则指向以 JNI_FALSE 填充的 jboolean
 
    void (JNICALL *ReleaseBooleanArrayElements)
      (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode);
    void (JNICALL *ReleaseByteArrayElements)
      (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode);
    void (JNICALL *ReleaseCharArrayElements)
      (JNIEnv *env, jcharArray array, jchar *elems, jint mode);
    void (JNICALL *ReleaseShortArrayElements)
      (JNIEnv *env, jshortArray array, jshort *elems, jint mode);
    void (JNICALL *ReleaseIntArrayElements)
      (JNIEnv *env, jintArray array, jint *elems, jint mode);
    void (JNICALL *ReleaseLongArrayElements)
      (JNIEnv *env, jlongArray array, jlong *elems, jint mode);
    void (JNICALL *ReleaseFloatArrayElements)
      (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode);
    void (JNICALL *ReleaseDoubleArrayElements)
      (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode);
这些函数用于通知虚拟机指针已经不再需要 .
其中 mode  的参数有
0 =在更新数组元素后释放 elems 缓冲器
JNI_COMMIT =在更新数组元素后不释放 elems 缓冲器
JNI_ABORT =不更新数组元素释放 elems 缓冲器
 
 void (JNICALL *GetBooleanArrayRegion)
      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf);
    void (JNICALL *GetByteArrayRegion)
      (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
    void (JNICALL *GetCharArrayRegion)
      (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf);
    void (JNICALL *GetShortArrayRegion)
      (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf);
    void (JNICALL *GetIntArrayRegion)
      (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf);
    void (JNICALL *GetLongArrayRegion)
      (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf);
    void (JNICALL *GetFloatArrayRegion)
      (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf);
    void (JNICALL *GetDoubleArrayRegion)
      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf);
 
    void (JNICALL *SetBooleanArrayRegion)
      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf);
    void (JNICALL *SetByteArrayRegion)
      (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf);
    void (JNICALL *SetCharArrayRegion)
      (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf);
    void (JNICALL *SetShortArrayRegion)
      (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf);
    void (JNICALL *SetIntArrayRegion)
      (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf);
    void (JNICALL *SetLongArrayRegion)
      (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf);
    void (JNICALL *SetFloatArrayRegion)
      (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf);
    void (JNICALL *SetDoubleArrayRegion)
      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf);
这些函数用于访问和设置局部元素 .
其他函数请参照 jni.h
 
. JavaC连动参数的传递
还有我要和你讨论的是参数传递有值传递和地址 ( 还有引用传递 ) 传递的两种方式 . 在它们连动时我们也要进行这两种传递的实现 .
 
我们知道 Java 参数传递都是值传递 , 而没有地址传递的说法 . 但是为了带回参数的变化值 ( 你不可能把所有的信息都在函数返回值里返回 ), 我们不得不创造一个等价的地址传递方式 .
幸运的是 Java 里的对象是可以作为参数传递给函数并且可以带回其在函数中的变化 ( 从内部实现机制看 , 其实就是一种引用传递 ).
于是我们的出结论 :
Java 中传递用传递值静态对象时为值传递 , new 传递对象引用传递 .
 
我们要编写这样的一个函数 : 将一个 byte[] 里的内容拷贝到另一个 byte[] 
int javabytecpy( byte[] dest,  byte [] src,  int req_byte_len);
我们的 java 文件内容为
package java2c.testdll;
import java.io.UnsupportedEncodingException;
public class javatest {
         public static void main(String args[]){
        
                   int rtn = 0;
                   String str=" 你好我的祖国 --China";
                   byte[] src_byte_array = str.getBytes();
                   byte[] dest_byte_array =new byte[src_byte_array.length];
                   System.out.println(" 拷贝前源 byte 数组内容为 : " +BytearrayToStgring(src_byte_array));
                   System.out.println(" 拷贝后目标 byte 数组内容为 :"+BytearrayToStgring(dest_byte_array));
                   System.out.println("DLL  函数返回值为 "+rtn);
                   rtn = javabytecpy(dest_byte_array, src_byte_array, 6);
                   System.out.println(" 拷贝前源 byte 数组内容为 : " +BytearrayToStgring(src_byte_array));
                   System.out.println(" 拷贝后目标 byte 数组内容为 :"+BytearrayToStgring(dest_byte_array));
                  
                   System.out.println("DLL  函数返回值为 "+rtn);
         }
         //  加载库
         static {
                   //  显示 java.library.path 内容
                   System.out.println(System.getProperty("java.library.path"));
                   //  在这里加载的是 C/C++ 生成的 DLL 文件名 , 这里是 java_c_dll.dll
                   System.loadLibrary("java_c_dll");
                   System.out.println("------------------DLL Started--------------------------");
         }
         /**
         * 参数 :
         *dest  目标数组                                 对象传递
         *src  源数组                                     对象传递
         *dest_byte_len  需要拷贝长度    值传递
         * 返回值 :
         * 成功  0 , 失败  -1
         **/
         public native static int javabytecpy( byte[] dest, byte [] src, int req_byte_len);
        
    public static String BytearrayToStgring(byte[] byte_in){
        try{
            String encoding="GB2312";
            String ret_str=new String(byte_in,encoding);
            return ret_str;
        }
        catch(UnsupportedEncodingException exp){
             return "";
        }
    }
 
} 生成的头文件为
java2c_testdll_javatest.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class java2c_testdll_javatest */
 
#ifndef _Included_java2c_testdll_javatest
#define _Included_java2c_testdll_javatest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     java2c_testdll_javatest
 * Method:    javabytecpy
 * Signature: ([B[BI)I
 */
JNIEXPORT jint JNICALL Java_java2c_testdll_javatest_javabytecpy
 (JNIEnv *, jclass, jbyteArray, jbyteArray, jint);
 
#ifdef __cplusplus
}
#endif
#endif
我们的 C/C++ 实现文件为
java2c_testdll_javatest.cpp
#include "stdio.h"
#include "jni_md.h"
#include "java2c_testdll_javatest.h"
/*
 * Class:     java2c_testdll_javatest
 * Method:    execute
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_java2c_testdll_javatest_javabytecpy
          (    JNIEnv *   env,
               jclass     cls,
               jbyteArray dest_byte_array,
               jbyteArray src_byte_array,
               jint       req_len){
               printf("DLL 调用开始 ./n");
               if ( env->GetArrayLength(src_byte_array) < req_len ){
                    printf(" 你需要的长度超过源 byte 数组 ./n");
                    return -1;
               };
               if ( env->GetArrayLength(dest_byte_array) < env->GetArrayLength(src_byte_array)){
                    printf(" 你的目标数组小于源数组 ./n");
                    return -1;
               };
               jbyte* byte_temp = env->GetByteArrayElements(src_byte_array, JNI_FALSE);
               env->SetByteArrayRegion(dest_byte_array, 0, req_len, (const jbyte*)byte_temp);
               printf("DLL 调用结束 ./n");
          return 0;
};
 
我们运行的结果是
C:/WINNT/system32;.;C:/WINNT/system32;C:/WINNT;C:/WINNT/system32;C:/WINNT;C:/WINNT/System32/Wbem;D:/Program Files/Microsoft Visual Studio/Common/Tools/WinNT;D:/Program Files/Microsoft Visual Studio/Common/MSDev98/Bin;D:/Program Files/Microsoft Visual Studio/Common/Tools;D:/Program Files/Microsoft Visual Studio/VC98/bin;D:/Java/jdk1.5.0_02/bin
------------------DLL Started--------------------------
拷贝前源 byte 数组内容为 你好我的祖国 --China
拷贝前目标 byte 数组内容为 :                  
DLL  函数返回值为 0
拷贝后源 byte 数组内容为 你好我的祖国 --China
拷贝后目标 byte 数组内容为 : 你好我             
DLL  函数返回值为 0
DLL 调用开始 .
DLL 调用结束 .
 
这个例子中我们看到了函数传递参数的方法 . 限于篇幅,我们也不深入讨论了 .
C/C++ 端的编程大家可以参照 jni.h 里的各种声明 , 我想熟悉 C/C++ 的都可以看的明白 . 并很快熟练地掌握 . 你必须保证你的 C/C++ 程序正确而且没有内存泄露,否则你的虚拟机将会捕捉到无法处理的异常而退出或者崩溃 . 你可能会花费很多时间才能找到错误 . 所以我们的程序必须经过严格的测试才能应用 .
还有一点提醒大家,与 C/C++ 函数传递参数的时候请你对字符的转换一下, 因为 java 字符 unicode 编码的 , C/C++ 中有选择的 , 普通的是 ascii , 你在实际开发过程中 , 请参照相关的 Java unicode 解码编码的资料 .
 
 
 
 
附录一
javah
功能说明:
头文件和  Stub  文件生成器。 javah   Java  类生成  C  头文件和  C  源文件。这些文
件提供了连接胶合,使  Java   C  代码可进行交互。
语法:
javah [  命令选项  ] fully-qualified-classname. . .
javah_g [  命令选项  ] fully-qualified-classname. . .
补充说明:
javah  生成实现本地方法所需的  C  头文件和源文件。 程序用生成的头文件和源文件在
本地源代码中引用某一对象的实例变量。 .h  文件含有一个  struct  定义,该定义的布局
与相应类的布局平行。该  struct  中的域对应于类中的实例变量。
头文件名以及在头文件中所声明的结构名都来源于类名。如果传给  javah  的类是在某个
包中,则头文件名和结构名前都要冠以该包名。下划线  (_)  用作名称分隔符。
缺省情况下, javah  为每个在命令行中列出的类都创建一个头文件,且将该文件放在当
前目录中。用  -stubs  选项创建源文件。用  -o  选项将所有列出类的结果串接成一个单
一文件。
缺省情况下, javah  为每个在命令行中列出的类都创建一个头文件,且将该文件放在当
前目录中。用  -stubs  选项创建源文件。用  -o  选项将所有列出类的结果串接成一个单
一文件。
命令选项
-o[ 输出文件 将命令行中列出的所有类的头文件或源文件串接到输出文件中。 -o   -
两个选项只能选择一个。
-d[ 目录 设置  javah  保存头文件或  stub  文件的目录。 -d   -o  两个选项只能选择一
个。
-stubs  使  javah   Java  对象文件生成  C  声明。
-verbose  指明长格式输出,并使  javah  将所生成文件的有关状态的信息输出到标准输
出设备中。
-help  输出  javah  用法的帮助信息。
-version  输出  javah  的版本信息。
-jni  使  javah  创建一输出文件,该文件包含  JNI  风格的本地方法函数原型。这是缺省
输出,所以  -jni  的使用是可选的。
-classpath[ 路径 指定  javah  用来查询类的路径。如果设置了该选项,它将覆盖缺省
值或  CLASSPATH  环境变量。目录用冒号分隔。
-bootclasspath[ 路径 指定加载自举类所用的路径。缺省情况下,自举类是实现核心
Java  平台的类,位于  jrelib
t.jar   jrelibi18n.jar  中。
-old  指定应当生成旧  JDK1.0  风格的头文件。
-force  指定始终写输出文件 .

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、 1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READmE.文件(md如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通;、本 3项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看ReadmE.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、资 1源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READMe.m文件(如d有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值