Android 三天学会JNI之一基础知识C

一 JNI知识复习(在前面的文章也有提到,这里只是复习)

JNI java native interface 即java原生接口

实现java代码和原生代码进行互相调换,例如(c/c++)代码

为什么要进行交互?

首先 Java语言提供的类库无法满足要求,且在数学运算,实时渲染的游戏上,音视频处理等方面上C/C++相比效率稍低

然后, Java语言无法直接操作硬件,C/C++代码不仅能操作硬件而且还能发挥硬件最佳性能

最后 使用Java调用本地的C/C++代码所写的库,省去了重复开发的麻烦,并且可以利用很多开源的库提高程序效率Android 三天学会JNI之一基础知识C

从android 四层架构来分析 应用层 , 应用框架层 ,系统library库,和linux内核层, 蓝色是java代码编写 ,绿色是c,c++代码编写.     其实在framework层想要去调取library就需要使用到jni,例如我们打开相机应用,系统就会通过jni调用相机相关类库.只不过这些JNI谷歌大佬已经帮我们写好了.

二 C语言常见术语

库函数:

|-  为了代码重用,在C语言中提供了一些常用的用于执行一些标准任务(如输入/)的函数,这些函数事先被编译,并生成目标代码,然后将生成的目标代码打包成一个库文件以供再次使用库文件中的函数被称为库函数库文件被称为函数库

|-  在Windows中C语言库函数中的中间代码都是以.obj为后缀的,Linux中是以 .o为后缀。

提示:单个目标代码是无法直接执行的,目标代码在运行之前需要使用连接程序将目标代码和其他库函数连接在一起后生成可执行的文件。 Windows下.dll的文件 , linux下 .so .a的文件.

头文件:xxx.h

|-  头文件中存放的是对某个库中所定义的函数类型全局变量等进行声明,它类似于一份仓库清单。若用户程序中需要使用某个库中的函数,则只需要将该库所对应的头文件include到程序中即可。

   |-  头文件中定义的是库中所有函数函数原型。而函数的具体实现则是在库文件中。

   |-  简单的说:头文件是给编译器用的,库文件是给连接器用的。

|-  在链接器连接程序时,会依据用户程序中导入的头文件,将对应的库函数导入到程序中。头文件以.h为后缀名。


函数库:

|-  动态库:在编译用户程序时不会将用户程序内使用的库函数连接到用户程序的目标代码中,只有在运行时,且用户程序执行到相关函数时才会调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小

|-  静态库:在编译用户程序时会将其内使用的库函数连接到目标代码中,程序运行时不再需要静态库使用静态库生成可执行文件比较大


在Linux中:

|-  静态库命名一般为:lib+库名+.a

|-  如:libcxy.a 其中lib说明此文件是一个库文件cxy库的名称.a说明是静态的

|-  动态库命名一般为:lib+库名+.so 。.so说明是动态的

交叉编译:

|-  将中间代码连接成当前计算机可执行的二进制程序时,连接程序会根据当前计算机的CPU操作系统类型来转换。

根据运行的设备的不同,可以将cpu分为:

|-  arm结构 :主要在移动手持嵌入式设备上

|-  x86结构 : 主要在台式机笔记本上使用。如Intel和AMD的CPU 。

若想在使用了基于x86结构CPU的操作系统中编译出可以在基于arm结构CPU的操作系统上运行的代码,就必须使用交叉编译

交叉编译:一个平台下编译出在另一个平台中可以执行的二进制代码。Google提供的NDK就可以完成交叉编译的工作。


NDK全称:Native Development Kit 。

|-  NDK是一系列工具的集合它有很多作用

   |-  首先,NDK可以帮助开发者快速开发C(或C++)的动态库

   |-  其次,NDK集成了交叉编译器。使用NDK,我们可以将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率

NDK工具必须在Linux下运行,它可以在linux环境下编译出可以在arm平台下运行的二进制库文件。


使用JNI技术,其实就是在Java程序中,调用C语言函数库中提供的函数,来完成一些Java语言无法完成的任务。由于Java语言和C语言结构完全不相同,因此若想让它们二者交互,则需要制定一系列的规范。JNI就是这组规范,此时 Java只和JNI交互,而由JNI去和C语言交互。

 

JNI技术分为两部分:JavaC语言端。且Java端为主导

|-  首先,Java程序员在Java端定义一些native方法,并将这些方法C语言头文件的方式提供给C程序员

|-  然后,C程序员使用C语言,来实现Java程序员提供的头文件中定义的函数

|-  接着,C程序员将函数打包成一个库文件,并将库文件交给Java程序员

|-  最后,Java程序员Java程序中导入库文件,然后调用native方法。

 

在Java程序执行的时候,若在某个类中调用了native方法,则虚拟机会通过JNI来转调用库文件中的C语言代码。提示:C代码最终是在Linux进程中执行的,而不是在虚拟机中


三 C语言基础知识

#C基本数据类型
* short:2
* int:4
* long:4
* float:4
* double:8

* char:1

*signed  *unsigned

这个和java略有区别 java整型还有byte 一个字节 ,并且java中long是8个字节 char是占用2个字符


#C语言的输出

*%d  int

*%ld  long int

*%lld  long long 

*%hd  short

*%c  char

*%f  float

*%lf  double

*%u  无符号数

*%x  十六进制输出int 或long int 或 long long 或short 

*%o  八进制输出 

*%s  字符串 


#C中内存地址

* 内存的门牌号
* 内存中所有数据都是通过地址拿到的
* 没有地址的内存是无法访问
* 32位系统能表示的最大内存是4G
* 因为32位系统的内存总线长度是32位,也就是可以用于分配给内存作为地址的数字是 2的32次方 个

* 内存中每个字节都有一个地址

#内存修改器
* 原理:比方说修改血量,血量一定是保存在内存中的一个变量,找到这个变量的地址,修改地址上的值
#指针变量
* 保存的值是一个内存地址
* 定义方式 int* p:指针指向的内存地址上存放的数据是一个int型
* *p:引用指针指向的内存地址上存放的数据

* int** q:定义二级指针,二级指针存放的是一个一级指针的地址

例如 :

Android 三天学会JNI之一基础知识C

结果:

Android 三天学会JNI之一基础知识C

分析:

Android 三天学会JNI之一基础知识C


#常见错误
* 指针赋值之前,不要使用(给*p赋值)
* 未赋值的指针称为野指针
* 指针的类型不要混用


#值传递和引用传递
* 值传递:传递一个普通的值
* 引用传递:传递一个内存地址,其实所有传递都叫值传递,引用传递传递的值是一个地址


#数组
* 数组的内存空间是连续的
* 数组变量保存的是首地址(第0个元素的地址)

#栈
* 内存空间是连续的
* 自动分配
* 大小固定
* 系统自动释放
* 栈上分配的内存叫静态内存
#堆
* 程序员手动申请
* java:new
* c:malloc
* 大小不固定,取决于系统虚拟内存
* 程序员手动释放
* java:自动
* c:free函数
* 空间不连续

* 堆上分配的内存叫动态内存

贴上一段C语言结构体代码:

#include<stdio.h>
#include<stdlib.h>
void study(){
printf("好好学习天天向上\n"); 
}


struct student{
int age;
int height;
char sex;

void (*studyp)(); 
};
main(){

struct student stu = {20,178,'f',study}; 
//第一种输出 
stu.studyp(); 

//第二种输出  调用函数指针 
struct student* stup = &stu; 
(*stup).studyp();

//引用这个指针指向的结构体的属性
stup -> studyp(); 


system("pause"); 

}