一、宏定义
宏定义可以理解为就是定义一个常量或一个函数,实现复用,易于统一维护和修改。
// 不带参数的宏定义
#define MAX 10
// 带参宏定义
#define M(y) y * y + 3 * y
// 宏调用
k = M(5);
二、JNIEXPORT
和 JNICALL
JNIEXPORT
与 JNICALL
实际上是 JNI
中定义的两个宏,它们在 Windows
与 Linux
分别有不同的定义。
// Windows 系统
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#define JNIEXPORT __declspec(dllexport)
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stdcall
typedef long jint;
typedef __int64 jlong;
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */
// Linux 系统
#define JNIIMPORT
#define JNIEXPORT __attribute__ ((visibility ("default")))
#define JNICALL
三、JNIEXPORT
和 JNICALL
宏定义作用
-
JNIEXPORT
宏定义作用
如果我们的程序需要生成动态链接库 , 并且要把该动态链接库交给其它程序使用, 那么就需要在函数前加入特殊标识 , 才能在其它程序代码中调用该动态链接库中定义的函数 。动态链接库在Windows
系统和Linux
系统中通常分别是.dll
文件 和.so
文件。
那么根据不同系统中JNIEXPORT
宏定义的不同,在预编译时就会进行对应的宏替换。 -
JNICALL
宏定义作用-
Windows
系统中JNICALL
宏定义为__stdcall
,__stdcall
是一种函数调用约定 , 因为当程序编译为本地机器码由CPU
执行时,CPU
无法明确知道每个函数应该怎么传参,于是提供了栈结构来支持参数传递,但当调用函数有多个参数时,参数应该按照怎样的顺序入栈,然后函数调用完栈又应该由谁来清理,针对这两个问题,出现了一些函数调用约定,__stdcall
就是其中的一种,__stdcall
修饰的函数在调用时参数都是从右向左依次被压入到栈中,函数调用完在返回前由被调用函数自己负责清理堆栈。 -
Linux
系统中JNICALL
没有进行定义 , 直接置空, 因此在Linux
中是可以不用写JNICALL
宏的 。
-
四、JNIEXPORT
与 JNICALL
宏替换
-
Windows
系统 :
// 使用 JNIEXPORT 和 JNICALL 的原始方法
extern "C"
JNIEXPORT void JNICALL Java_bytecode_NativeTest_sayWithMsgAndNum(JNIEnv *jniEnv, jobject obj, jstring msg, jint num) {
// 函数体
}
// 预编译过程中宏替换后的方法
extern "C"
__declspec(dllexport) void __stdcall Java_bytecode_NativeTest_sayWithMsgAndNum(JNIEnv *jniEnv, jobject obj, jstring msg, jint num) {
// 函数体
}
-
Linux
系统
// 使用 JNIEXPORT 和 JNICALL 的原始方法
extern "C"
JNIEXPORT void JNICALL Java_bytecode_NativeTest_sayWithMsgAndNum(JNIEnv *jniEnv, jobject obj, jstring msg, jint num) {
// 函数体
}
// 预编译过程中宏替换后的方法
extern "C"
__attribute__ ((visibility ("default"))) void Java_bytecode_NativeTest_sayWithMsgAndNum(JNIEnv *jniEnv, jobject obj, jstring msg, jint num) {
// 函数体
}
网友评论