1.写一个调用的C程序的类
例如一个简单的字符串输入输出类:
package com.lxy;
public class TestC {
static{
System.loadLibrary("c");
}
public native int get();
public native void set(String a);
}
System.loadLibrary("c");
命令行在文件目录中运行命令javac 类.java
本例中因为class文件在com.lxy包下,所以执行命令:
"C:\Users\TestC\src>javac com\lxy\TestC.java"
执行命令:
javah -classPath (class路径) -jni com.lxy.TestC
本例中执行:
C:\Users\TestC\src>javah com.lxy.TestC
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_lxy_TestC */
#ifndef _Included_com_lxy_TestC
#define _Included_com_lxy_TestC
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_lxy_TestC
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_lxy_TestC_get
(JNIEnv *, jobject);
/*
* Class: com_lxy_TestC
* Method: set
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_lxy_TestC_set
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
头文件中,get方法
JNIEXPORT jint JNICALL Java_com_lxy_TestC_get (JNIEnv *, jobject);
和set方法
JNIEXPORT void JNICALL Java_com_lxy_TestC_set (JNIEnv *, jobject, jstring);
新建c文件"TestC.c"
#include "com_lxy_TestC.h"
#include
#include
#include
#include "stdlib.h"
#include "string.h"
char* jstringToWindows( JNIEnv *env, jstring jstr );
jstring WindowsTojstring( JNIEnv* env, const char* str );
const char *s;
//实现get方法
JNIEXPORT jstring JNICALL Java_com_lxy_TestC_get
(JNIEnv *env, jobject o)
{
jstring str = WindowsTojstring(env,s);
return str;
}
//实现set方法
JNIEXPORT void JNICALL Java_com_lxy_TestC_set
(JNIEnv *env, jobject obj, jstring param)
{
const char *buf;
//将jstring转换为C语言的char,编码格式为UTF-8
//buf = (*env)->GetStringUTFChars(env,param, 0);//这样使用会造成中文乱码
buf=jstringToWindows( env, param );//调用这个函数可以避免中文乱码
s = buf;
printf("printf:%s", s);
//使用完成后清除占用的内存。注意在这里还不能清除,因为清除后s也没了。
//(*env)->ReleaseStringUTFChars(env, param, buf);
}
//将JNI的jstring转换成c语言的char数组
char* jstringToWindows( JNIEnv *env, jstring jstr )
{
int length = (*env)->GetStringLength(env,jstr );
const jchar* jcstr = (*env)->GetStringChars(env,jstr, 0 );
char* rtn = (char*)malloc( length*2+1 );
int size = 0;
size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );
if( size <= 0 )
return NULL;
(*env)->ReleaseStringChars(env,jstr, jcstr );
rtn[size] = 0;
return rtn;
}
//将c语言的char数组转换成JNI的jstring
jstring WindowsTojstring( JNIEnv *env, const char* str )
{
jstring rtn = 0;
int slen = strlen(str);
unsigned short* buffer = 0;
if( slen == 0 )
rtn = (*env)->NewStringUTF(env,str );
else
{
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
buffer = malloc( length*2 + 1 );
if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
rtn = (*env)->NewString( env, (jchar*)buffer, length );
}
if( buffer )
free( buffer );
return rtn;
}
http://blog.csdn.net/fei0724/article/details/11145031
5.将C程序编译并链接为dll共享库:
这里使用tdm64-gcc-5.1.0-2来编译C程序。
因为include了
gcc -fpic -shared TestC.c -oc.dll -I(h文件路径)
6.写一个测试类调用方法
package com.lxy;
public class Test {
public static void main(String[] args) {
TestC t = new TestC();
t.set("abc");
System.out.println(t.get());
}
}
http://enijmax.2y.idv.tw/linux/CLib_Jni.html
顺便将C语言编译器gcc的命令简单摘要下:
1.gcc main.c -o main //可以将main.c文件编译为main.exe可执行文件 -o是命名为
2.如果main中引用了其他C文件的方法则:
gcc main.c a.c -o main //将所有引用的c文件一起编译,中间用空格区分
如果工程中有多个文件,可以使用make来编译。
3.要编译为dll文件则:
gcc -shared -fpic main.c a.c -o main.dll
4.如果有include其他.h文件,要告诉编译器引用的h文件的路径:
gcc main.c a.c -o main -I path
5.如果要引用lib库文件,比如引用libmylib.a,其路径在libPath:
gcc main.c -o main -l mylib -L libPath
如果项目中关联的文件较多,用gcc则显得不便。应该使用Makefile。
关于Makefile,可以参考:
http://www.chinaunix.net/old_jh/23/408225.html