Java通过JNI调用C

Java调用C有多种方式,本文介绍笔者最近的学习过程,避免今后再犯类似的错误。

首先,Java肯定是调用C的动态链接库,即通过编译器编译后的dll/so文件。

下面介绍gcc编译dll的方法。

一般情况把主函数,子函数定义,子函数声明(全局变量,宏等)分别放在不同的文件中。

我们主要对子函数编译生成可用的dll,供主函数调用。

有一个工程,里面有三个文件,分别是

#include <stdio.h>
#include "test.h"

int main(int argc, char *argv[]) {
    
    printf("2 + 3 = %d\n", sum(2, 3));
    return 0;
}
main.c
1 #include <stdio.h>
2 #include"test.h"
3 
4 int sum(int a, int b)
5 {
6     return a + b;
7 }
test.c
#ifndef _TEST_H_DEVC_
#define _TEST_H_DEVC_

int sum(int a, int b);

#endif
test.h

假如想在main.c中调用test.c函数的dll文件,可以编译test.c的动态链接库

在Windows平台上安装MinGW, 即可模拟Linux下的gcc的编译器。

得到test.dll文件。接着把,main.c 、test.h、test.dll 放到另一个文件夹中,编译得到

可执行文件,rs.exe。运行结果得到

 

 

 

下面介绍javah编译C的头文件,本文主要介绍在MyEclipse下的运行步骤。

先配置javah命令如下:

 

其中,需要自主配置一下三个参数

Location:是你本机的javah.exe所在的路径。

Working Directory: ${project_loc}/bin

Arguments: -classpath .;./classes -d "${project_loc}" -jni ${java_type_name}

配置好后,就可以一键操作生成java所需要的头文件了。

例子如下:

工程名字:zz-testdll

 1 package main;
 2 
 3 import testdll.Sum;
 4 
 5 public class Main {
 6     static{
 7         System.loadLibrary("test");
 8     }
 9     public static void main(String[] args){
10         int rs = Sum.mSum();
11         System.out.println(rs);
12     }
13 }
Main.Java
1 package testdll;
2 
3 public class Sum {
4     public native static int mSum();
5 }
Sum.Java

选中Sum.Java文件,然后运行配置好的javah命令,即可得到上图中的testdll_Sum.h文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class testdll_Sum */

#ifndef _Included_testdll_Sum
#define _Included_testdll_Sum
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     testdll_Sum
 * Method:    mSum
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_testdll_Sum_mSum
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif
testdll_Sum.h

下面要实现testdll_Sum.h文件中的方法

(因为gcc编译器和VC++编译器的实现方式的不同,参看http://www.blogjava.net/lixf/archive/2006/01/09/25177.html)

我们需要修改生成的testdll_Sum.h中方法的名字,在函数的名字前面加一个下划线即可。

更改后的testdll_Sum.h如下:

 1 /* DO NOT EDIT THIS FILE - it is machine generated */
 2 #include <jni.h>
 3 /* Header for class testdll_Sum */
 4 
 5 #ifndef _Included_testdll_Sum
 6 #define _Included_testdll_Sum
 7 #ifdef __cplusplus
 8 extern "C" {
 9 #endif
10 /*
11  * Class:     testdll_Sum
12  * Method:    mSum
13  * Signature: ()I
14  */
15 JNIEXPORT jint JNICALL _Java_testdll_Sum_mSum
16   (JNIEnv *, jclass);
17 
18 #ifdef __cplusplus
19 }
20 #endif
21 #endif
testdll_Sum.h

实现的方法如下:

#include "testdll_Sum.h"

//前两个参数(env和obj)可以忽略
JNIEXPORT jint JNICALL _Java_testdll_Sum_mSum
  (JNIEnv * env, jclass obj)
  { 
     printf("Hello world!\n");
     return 5;
  }
Sum.c

在Java的include文件夹下得到三个文件,一共5个文件供编译使用。

 

 

得到test.dll,放在Java工程的运行目录下即可。

选中Main.Java文件,run,得到

 

 

在我写完后,得知Java通过JNA可以很方便的调用C文件,有机会学习下。

以上内容,仅供参考。

 

posted @ 2014-11-25 19:10  kongmeng  阅读(259)  评论(0编辑  收藏  举报