java程序中调用c语言库

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");

表示在目录中找"c.dll"的动态链接库文件。
类中用native声明各接口方法。


2.编译类

命令行在文件目录中运行命令javac 类.java

本例中因为class文件在com.lxy包下,所以执行命令:

"C:\Users\TestC\src>javac com\lxy\TestC.java"




3.用上一步生成的class文件生成C的头文件

执行命令: 

javah -classPath (class路径) -jni com.lxy.TestC

本例中执行:

C:\Users\TestC\src>javah com.lxy.TestC


此时会在当前目录下生成 "com_lxy_TestC.h" 头文件:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* 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



4.实现C程序的功能

头文件中,get方法

JNIEXPORT jint JNICALL Java_com_lxy_TestC_get  (JNIEnv *, jobject);

和set方法
JNIEXPORT void JNICALL Java_com_lxy_TestC_set  (JNIEnv *, jobject, jstring);

声明了C程序功能暴露的公共接口。我们需要实现这些方法:


新建c文件"TestC.c"

#include "com_lxy_TestC.h"
#include <jni.h>
#include <windows.h>
#include <stdio.h>
#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;
}


关于jstring和char的转换问题,参考自文章:

http://blog.csdn.net/fei0724/article/details/11145031


5.将C程序编译并链接为dll共享库:
这里使用tdm64-gcc-5.1.0-2来编译C程序。
因为include了<jni.h>,需要让编译器知道该文件及其引用的<jni_md.h>在哪。可以从JAVA_HOME\include及JAVA_HOME\include\win32下找到他们,复制到c文件目录下。然后在c文件目录下执行命令:

gcc -fpic -shared TestC.c -oc.dll -I(h文件路径)

其中-fpic是输出的对象模块式按照可重定位地址方式生成。
-shared表示生成动态链接库文件
TestC.c是要用哪个文件生成
-o指定输出的文件名为c.dll(与java中System.loadLibrary("c")一致)
-Ipath 告诉编译器从哪里找.h文件
如果没有错误,此时dll文件已经生成在当前目录了。
将dll文件放到项目根目录下,即可运行调用。注:要放在根目录或java.library.path中。



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());
	}

}

关于java调用C的生成,参考:

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




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java程序中调用GPIO信号的读写,需要使用Java Native Interface(JNI)技术,将Java代码和C语言代码相结合。具体步骤如下: 1. 编写C语言函数 编写C语言函数,实现GPIO信号的读写操作。函数需要包含在Java程序中进行调用,可以使用System.loadLibrary()方法加载动态链接。 2. 定义Java本地接口 在Java程序中定义Java本地接口,将Java代码和C语言代码相连接。本地接口需要使用native关键字声明,如下所示: ``` public class GPIO { public native int gpioRead(int pin); public native void gpioWrite(int pin, int value); static { System.loadLibrary("gpio"); } } ``` 在上面的代码中,gpioRead和gpioWrite方法是调用C语言函数中实现的GPIO信号读写操作的Java本地接口。 3. 编写C语言函数 编写C语言函数,实现GPIO信号的读写操作。函数需要使用Java本地接口声明的参数和返回值类型,如下所示: ``` JNIEXPORT jint JNICALL Java_GPIO_gpioRead(JNIEnv *env, jobject obj, jint pin) { // 读取GPIO信号的值 return value; } JNIEXPORT void JNICALL Java_GPIO_gpioWrite(JNIEnv *env, jobject obj, jint pin, jint value) { // 写入GPIO信号的值 } ``` 在上面的代码中,Java_GPIO_gpioRead和Java_GPIO_gpioWrite函数是实现GPIO信号读写操作的C语言函数。参数env和obj是JNI环境和Java对象,pin和value是GPIO信号的编号和值。 4. 编译和打包Java程序 使用javac命令编译Java程序,生成.class文件。使用jar命令打包Java程序,生成.jar文件。 5. 编译C语言函数 使用gcc命令编译C语言函数,生成.so文件。在编译命令中需要包含Java头文件和JNI文件,如下所示: ``` gcc -shared -fpic -o libgpio.so gpio.c -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -L${JAVA_HOME}/jre/lib/amd64/server -ljvm ``` 在上面的命令中,-I选项指定Java头文件的路径,-L选项指定JNI文件的路径,-ljvm选项指定JNI文件的名称。 6. 运行Java程序 使用java命令运行Java程序,即可调用GPIO信号的读写操作。 总之,通过JNI技术,Java程序可以调用C语言函数中实现的GPIO信号读写操作,实现对GPIO信号的控制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值