关于学习NDK基础知识这些就够了(七)

1、C语言执行的流程

编译:形成目标代码(.obj)

连接:将目标代码与C函数库连接合并,形成最终的可执行文件

预编译(预处理),为编译做准备工作,完成代码文本的替换工作
例如我们的导入文件时

void main(){
    #include "my.txt"
    printf("%s\n", "I am a little boy!");
    getchar();
}

当我们在vs中写一个txt文件,当我导入时这就相当于一个预编译的过程
完成了一个代码文本的替换过程

一般我们的预编译的文件在
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include目录下

头文件告诉编译器有这样一个函数,连接器负责找到这个函数的实现

2、宏定义、宏替换、预编译指令

define指令

1.定义标示
#ifdef __cplusplus 标识支持C++语法
#ifdef ANDROID //是否支持安卓
2防止文件重复引入
//如果没有定义AH,定义AH
#ifndef AH
#define AH
#include "B.h"

void printfA();

#endif//有if就需要有endif

或者这样写

//该头文件只被包含一次,让编译器自定处理好循环包含问题
#pragma once
#include "B.h"

void printfA();
3.定义常数(便于修改与阅读)
#define MAX 100

void main(){
    int i = 90;
    if (i < MAX){
        printf("比MAX小..");
    }
    getchar();
}
4定义宏函数
void ms_com_jni_read(){
    printf("read\n");
}

void ms_com_jni_write(){
    printf("write\n");
}

//NAME是参数
#define jni(NAME) ms_com_jni_##NAME();
//webrtc JNI函数名称很长,也是JOW宏函数缩短函数名称

void main(){
    jni(write);//替换:ms_com_jni_write();
    //替换成:printf("INFO:"); printf("%s%d","大小:",89);
    getchar();
}
上边是函数无参的,当有参数的时候
//日志输出
//...是很多参数的意思
//__VA_ARGS__可变参数
//#define LOG(FORMAT,...) printf(##FORMAT,__VA_ARGS__); 
日志会有级别
//#define LOG_I(FORMAT,...) printf("INFO:"); printf(##FORMAT,__VA_ARGS__); 
//#define LOG_E(FORMAT,...) printf("ERRO:"); printf(##FORMAT,__VA_ARGS__); 

//升级版本
#define LOG(LEVEL,FORMAT,...) printf(##LEVEL); printf(##FORMAT,__VA_ARGS__);
#define LOG_I(FORMAT,...) LOG("INFO:",##FORMAT,__VA_ARGS__);
#define LOG_E(FORMAT,...) LOG("ERROR:",##FORMAT,__VA_ARGS__);
#define LOG_W(FORMAT,...) LOG("WARN:",##FORMAT,__VA_ARGS__);

//在Android中
//#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"jason",FORMAT,##__VA_ARGS__);
//LOGI("%s","fix");
//替换
//__android_log_print(ANDROID_LOG_INFO, "jason", "%s", "fix");


void main(){
    LOG_E("%s%d","大小:",89);
    getchar();
}

3、JNI开发流程
JNI全称是Java Native Interface(Java本地接口)单词首字母的缩写,本地接口就是指用C和C++开发的接口。由于JNI是JVM规范中的一部份,因此可以将我们写的JNI程序在任何实现了JNI规范的Java虚拟机中运行。同时,这个特性使我们可以复用以前用C/C++写的大量代码。

   开发JNI程序会受到系统环境的限制,因为用C/C++语言写出来的代码或模块,编译过程当中要依赖当前操作系统环境所提供的一些库函数,并和本地库链接在一起。而且编译后生成的二进制代码只能在本地操作系统环境下运行,因为不同的操作系统环境,有自己的本地库和CPU指令集,而且各个平台对标准C/C++的规范和标准库函数实现方式也有所区别。这就造成使用了JNI接口的JAVA程序,不再像以前那样自由的跨平台。如果要实现跨平台,就必须将本地代码在不同的操作系统平台下编译出相应的动态库。

简单来说就是让C去访问Java 或者让java取访问我们的C的代码,就是为了代码提升效率,还有让我们的代码更加的安全

JNI开发流程主要分为以下8步:

    1.编写native方法
public class JniTest {

    public native static String getStringFromC();
    //这里的native修饰的方法,表示可以被C调用
    public static void main(String[] args) {

    }
}
2.javah命令,生成.h头文件
打开cmd命令,javah 包名加完整的类名生成.h文件
3.复制.h头文件到CPP工程中
在我们的vs中添加头文件,点击添加现有项,然后刷新
4.复制jni.h和jni_md.h文件到CPP工程中
这两个文件在我们的jdk的目录下搜索

最后就是这样的

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

#ifndef _Included_com_ms_jni_JniTest
#define _Included_com_ms_jni_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ms_jni_JniTest
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_ms_jni_JniTest_getStringFromC
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif
//这是我们生成的.h文件
5.实现.h头文件中声明的函数
#include "com_ms_jni_JniTest.h"

//函数实现
//这里我们的方法名的命名要求:Java_包名_类名_方法名,必须这样去写,
//不这样写,这个方法就调用不到
JNIEXPORT jstring JNICALL Java_com_ms_jni_JniTest_getStringFromC
(JNIEnv *env, jclass jcls){
    //JNIEnv 结构体指针
    //env二级指针
    //代表Java运行环境,调用Java中的代码

    //简单的实现
    //将C的字符串转为一个java字符串
    return (*env)->NewStringUTF(env,"C String");
}
6.生成dll文件

这里写图片描述

加载我们的dll动态库

public class JniTest {

    public native static String getStringFromC();

    public static void main(String[] args) {

    }

    //加载动态库
    static{
        System.loadLibrary("jni_study");
    }

}
7.配置dll文件所在目录到环境变量
配置环境变量到path
8.重启Eclipse
public class JniTest {

    public native static String getStringFromC();

    public static void main(String[] args) {
        String text = getStringFromC();
        System.out.println(text);
    }

    //加载动态库
    static{
        System.loadLibrary("jni_study");
    }

}

5、动态库和静态库的区别

动态库.dll :共享代码
静态库.a

6、JNIEnv

在C中:
JNIEnv 结构体指针别名
env二级指针

在C++中:
JNIEnv 是一个结构体的别名
env 一级指针

1.为什么需要传入JNIEnv,函数执行过程中需要JNIEnv
2.C++为什么没有传入?C++中进行了封装,传入了this所以不用再写
3.C++只是对C的那一套进行的封装,给一个变量赋值为指针,这个变量是二级指针

C/C++中为什么有区别?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值