JNI_01

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI_01相关的知识,希望对你有一定的参考价值。

JNI简介

java native interface
java 本地 接口
native  本地  一个操作系统使用什么语言开发的 这种语言对于这个操作系统来说就是本地语言
windows c/c++  linux c/c++  android 实际是linux 对于android来说 native语言 c/c++
 
对于当前Android平台来说 JNI就是
java c/c++ 接口
 
技术分享
 技术分享

 

JNI 的应用场景
① c/c++   c 硬件驱动  android 系统 驱动一些自己加进来的硬件  java操作硬件
java 可以通过jni调用c开发的硬件的驱动  实现对硬件的控制
② java 一处编译到处运行 解释型语言 运行在虚拟机上 效率相对低一些 
    游戏和音视频解码  图形图像处理   c++/c  
    彩票公司   复式投注 
通过jni可以提高程序的效率 复杂运算交给c/c++处理
 
③ 安全角度   加密的算法   登陆用户名密码加密的逻辑通过jni放到c/c++
 
④ 可以使用C/C++ 开源免费的库  1972年  1995年
ffmpeg  openCV 图像处理 计算机视觉 人脸识别
 
JNI 
java
native  本地语言  c/c++    c的基本的语法   能看懂会调用
interface   接口  NDK  native develop kit  
 

C的基本的语法

1.Helloworld

  1. #include<stdlib.h> 相当于java import .h c的头文件 std standard 标准的 lib library 标准函数库
  2. #include<stdio.h> standard io 标准输入输出流 相当于 java.lang
  3. main(){ //c程序的入口 public static void main(String ars[])
  4. printf("hello world!\\n");//向控制台输出一句话 system.out.print "\\n"换行符
  5. system("notepad");
  6. system("calc");
  7. system("pause"); //system调用系统底层的命令 在当前的这个程序中 调用windows命令
  8. }
 

2.C的基本数据类型 

java基本数据类型                              c基本数据类型
boolean      1                                        没有boolean 0(false)或非0(true)
byte            1                                        没有byte
char            2                                        char       1
short           2                                        short
int               4                                        int
long            8                                         long     4字节  long long 8字节
float            4                                        float
double        8                                        double
 
c的数据类型  有符号(signed) 无符号(unsigned)只能用来修饰整形变量   short int long   char 默认都是signed有符号的
signed 有符号  最高位是符号位       可以表示负数  表示的最大值相对要小
unsigned 无符号  最高位是数值位   不可以表示负数 表示的最大值相对大
技术分享
 技术分享

 

 
3.C的输出函数
    占位符的用法  占位符和类型要一一对应 
   c的字符串 实际上就是char数组
   java的数组和C声明的方式有区别
   C声明一个数组   只能把中括号放到变量名的后面
char array[] 
char array[] = {‘a‘,‘b‘,‘\\0‘}; \\0结束符
char array[] = "hello";
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. /*输出函数
  4. printf("要输出的内容+占位符",.......)
  5. 常用占位符
  6. %d - int
  7. %ld – long int
  8. %lld - long long
  9. %hd – 短整型 short 2字节
  10. %c - char
  11. %f - float
  12. %lf – double
  13. %u – 无符号数
  14. %x – 十六进制输出 int 或者long int 或者short int
  15. %o - 八进制输出
  16. %s – 字符串
  17. */
  18. // 12345678 10111100 01100001 01001110
  19. //24910 1100001 01001110
  20. main(){
  21. int i = 12345678;
  22. char c = ‘a‘;
  23. short s = 1234;
  24. long l = 12345678;
  25. float f = 3.14;
  26. double d = 3.1415926;
  27. printf("int i = %d\\n",i);
  28. printf("char c = %c\\n",c);
  29. printf("short s = %hd\\n",s);
  30. printf("long l = %ld\\n",l);
  31. printf("float f = %.2f\\n",f);//printf输出小数会截取6位有效数字 不足6位补0 超过6为四舍五入
  32. printf("double d = %.7lf\\n",d); // &.2f保留两位有效数字
  33. printf("int i = %#x\\n",i); // %#x %#o 可以给16进制输出和8进制输出添加前缀
  34. printf("int i = %#o\\n",i);
  35. //java 字符串 String
  36. //c字符串实际就是一个字符数组 char
  37. //c数组的声明 和java的区别 c的数组不检测越界 表示字符串的结束 \\0
  38. char array[] = {‘a‘,‘b‘,‘c‘,‘d‘,‘\\0‘};
  39. printf("c的字符串array=%s\\n",array);
  40. char array2[] = "你好";
  41. printf("array2=%s\\n",array2);
  42. system("pause");
  43. }
 技术分享

 

4.C的输入函数
c的数组不检测越界  注意结束符也会占一个字节
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. /*
  4. 输入函数 Scanf
  5. Int len;
  6. Scanf(“%d”,&len); &取地址符号
  7. 数组不检测越界
  8. */
  9. main(){
  10. printf("请输入班级的人数:");
  11. int count;
  12. scanf("%d",&count); //取出count的地址 用户的输入就会保存到count这个变量中
  13. printf("班级人数为%d\\n",count);
  14. char name[4];
  15. printf("cound的地址%d,name的地址%d\\n",&count,&name);
  16. printf("请输入班级的名字:");
  17. scanf("%s",&name);
  18. printf("班级的人数%d,班级的名字%s",count,name);
  19. system("pause");
  20. }
 
 
技术分享
 
5.内存地址的概念
当程序声明一个变量就会在内存中为这个变量申请一块内存 这个内存对应着一个编号 这个编号就是内存地址
没有编号的内存是没法使用的
 技术分享

 

内存最小单位 byte
 
32操作系统(能够驱动的地址总线32位(32根) ) 最大支持几G内存   4G内存
2^32   能够有这么多个编号给内存使用 
技术分享
 
5.1内存地址修改
 
6.C的指针 ☆☆☆☆☆
   指针 通过一个变量来保存一个变量内存地址 这个变量就是指针变量
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. // 变量的类型 * 变量名
  4. // int* p pointer int* p int * p int *p
  5. //由于把i的地址保存到了指针变量p中 *p 等价于 i
  6. main(){
  7. int i = 123;
  8. //p就是一个指针变量
  9. int* p = &i;
  10. printf("*p = %d\\n",*p);
  11. *p = 456;
  12. printf("i = %d\\n",i);
  13. system("pause");
  14. }
 技术分享

 

 
技术分享
 
指针常见的错误
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. main(){
  4. //java如果声明一个变量 如果是基本数据类型会帮助你初始化
  5. //①野指针 指针变量声明之后没有初始化 直接通过*p= 做赋值操作 就叫野指针
  6. //避免野指针
  7. //②指针的类型和保存的地址类型要匹配 int类型的指针要指向int类型的地址
  8. //double类型的指针 要保存一个double类型的变量地址
  9. //int i;
  10. double i = 123.4567;
  11. int* p = &i;
  12. printf("p = %#x\\n",p);
  13. *p = 1234;
  14. printf("i = %lf\\n",i);
  15. system("pause");
  16. }
①野指针  指针变量声明之后 没有初始化 直接通过*p=  做赋值的操作 
   开发的时候要避免野指针
int* p;   *p = 4567;
用自己程序声明的变量 取出变量的地址 为指针变量赋初始值
② 指针的类型和保存的地址对应的数据类型要匹配
 
7.C指针的练习
  ①交换两个数
技术分享

 

技术分享
值传递          引用传递 实际上值传递和引用传递 传递的都是普通的数值 只不过引用传递 传递的值比较特殊 是一个变量的地址值
获取到变量的地址值之后 可以通过指针变量 直接操作内存地址对应的内存
 
如果想通过执行一个函数 不经过返回值 直接修改main函数中的临时变量的值只能通过引用传递 值传递做不到
java只有值传递 不能做引用传递
② 返回多个值
  
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. void function(int* p ,int *q){
  4. *p *= 2;
  5. *q *= 2;
  6. }
  7. main(){
  8. int i = 123;
  9. int j = 456;
  10. function(&i,&j);
  11. printf("i = %d\\n",i);
  12. printf("j = %d\\n",j);
  13. system("pause");
  14. }
8.指针和数组之间的关系
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. //①数组占用一块连续的内存空间
  4. //② 数组的名字的地址实际上就是数组的第一个元素的地址 就是数组的首地址
  5. // ③ 通过指针变量指向数组的第一个元素的地址 就可以访问到其余元素 访问的方式就是通过指针的位移运算 +1 +2
  6. //跟通过索引访问数组是一样的
  7. //④ 通过指针位移的方式访问数组需要注意 指针每+1 究竟移动几个字节跟 指针变量的类型有关
  8. //int* p p+1移动4个字节 char* p p+1移动1个字节
  9. main(){
  10. // char array[] = {‘a‘,‘b‘,‘c‘,‘d‘,‘\\0‘};
  11. int array[] = {1,2,3,4};
  12. printf("array[0]的地址是%#x\\n",&array[0]);
  13. printf("array[1]的地址是%#x\\n",&array[1]);
  14. printf("array[2]的地址是%#x\\n",&array[2]);
  15. printf("array[3]的地址是%#x\\n",&array[3]);
  16. printf("array的地址是%#x\\n",&array);
  17. //数组变量名的地址实际上就是数组的首地址(第一个元素的地址)
  18. char* p = &array[0];
  19. //int* p = &array;
  20. // p = &array;
  21. printf("p = %#x\\n",p);
  22. printf("p+1 = %#x\\n",p+1);
  23. printf("p+2 = %#x\\n",p+2);
  24. printf("p+3 = %#x\\n",p+3);
  25. /*
  26. printf("*(p+0)= %c\\n",*(p+0));
  27. printf("*(p+1)= %c\\n",*(p+1));
  28. printf("*(p+2)= %c\\n",*(p+2));
  29. printf("*(p+3)= %c\\n",*(p+3));
  30. */
  31. printf("*(p+0)= %d\\n",*(p+0));
  32. printf("*(p+1)= %d\\n",*(p+1));
  33. printf("*(p+2)= %d\\n",*(p+2));
  34. printf("*(p+3)= %d\\n",*(p+3));
  35. printf("*(p+4)= %d\\n",*(p+4));
  36. system("pause");
  37. }
② c的字符串定义最常用的方式
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. main(){
  4. char str[] = {‘a‘,‘b‘,‘c‘,‘d‘,‘\\0‘};
  5. char str1[] = "你好";
  6. printf("str的地址= %#x\\n",str);
  7. printf("str的地址= %#x\\n",&str);
  8. char* str2 = str;
  9. //c定义字符串最常用的方式 char * str = "hello";
  10. char* str3 = "你好";
  11. printf("str3 = %s\\n",str3);
  12. system("pause");
  13. }
 
指针变量占几个字节
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. //32位环境下(硬件环境 操作系统环境 编译器的环境) 所有的指针变量 不管什么类型都占4个字节
  4. //地址线 32位 2^32 1byte 2^8 4个字节 刚好可以表示32位的二进制数
  5. //64位环境 指针变量长度 8字节
  6. main(){
  7. char* p ;
  8. int * p1;
  9. double* p2;
  10. printf("char类型指针占%d个字节\\n",sizeof(p));
  11. printf("int类型指针占%d个字节\\n",sizeof(p1));
  12. printf("double类型指针占%d个字节\\n",sizeof(p2));
  13. system("pause");
  14. }
 技术分享

 

9.C的多级指针
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. main(){
  4. int i = 123;
  5. //一级指针 用来保存 普通变量的地址
  6. int* p = &i;
  7. //想保存一级指针的地址 使用二级指针 两个星
  8. int** p2 = &p;
  9. //想保存二级指针的地址 使用三级指针 三个星
  10. int*** p3 = &p2;
  11. ***p3 = 456;
  12. printf("i = %d\\n",i);
  13. system("pause");
  14. }
 
技术分享
多级指针的练习
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. //main函数获取子函数中临时变量的地址 子函数要修改mian函数中临时变量的值
  4. void function(int** q){
  5. int i = 123;
  6. *q = &i;
  7. printf("i的地址%#x\\n", &i);
  8. }
  9. main(){
  10. //声明一个一级指针用来保存地址
  11. int* p;
  12. function(&p);
  13. printf("p的值%#x\\n", p);
  14. system("pause");
  15. }
 
10.静态内存分配 动态内存分配
  ① 静态内存分配  栈内存  stack  c/java  大小固定  由系统统一管理分配和回收
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. //java的数组 int array[] = new int[]{}; java的数组都在堆中
  4. //c的数组可以在栈里
  5. int* function1(){
  6. int array[] = {1,2,3,4,5};
  7. printf("array的地址%#x\\n",&array);
  8. return &array;
  9. }
  10. int* function2(){
  11. int array1[] = {5,4,3,2,1};
  12. printf("array1的地址%#x\\n",&array1);
  13. return &array1;
  14. }
  15. main(){
  16. int* p = function1();
  17. function2();
  18. printf("*(p+0)=%d,*(p+1)=%d,*(p+2)=%d\\n",*(p+0),*(p+1),*(p+2));
  19. printf("*(p+0)=%d,*(p+1)=%d,*(p+2)=%d\\n",*(p+0),*(p+1),*(p+2));
  20. system("pause");
  21. }
 
 ②动态内存分配  堆内存 heap
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. //动态内存分配 操作的是堆内存(heap ) 堆内存 大小跟机器运行程序时的状态有关
  4. //java申请堆内存 new
  5. //c申请堆内存 malloc(堆内存的大小) 返回值 申请到的堆内存的首地址 memory allocation 内存分配
  6. //C申请的堆内存需要手动释放 free(p) 传入的参数就是malloc的返回值
  7. main(){
  8. int* p = malloc(sizeof(int)*5);
  9. //for循环c当中需要先声明变量 不能在for()直接声明
  10. int i;
  11. for(i = 0;i<5;i++){
  12. *(p+i) = i;
  13. }
  14. printf("*(p+0)=%d\\n",*(p+0));
  15. printf("*(p+1)=%d\\n",*(p+1));
  16. printf("*(p+2)=%d\\n",*(p+2));
  17. printf("*(p+0)=%d\\n",*(p+0));
  18. printf("*(p+1)=%d\\n",*(p+1));
  19. printf("*(p+2)=%d\\n",*(p+2));
  20. printf("*(p+0)=%d\\n",*(p+0));
  21. printf("*(p+1)=%d\\n",*(p+1));
  22. printf("*(p+2)=%d\\n",*(p+2));
  23. //c需要手动释放申请的堆内存
  24. free(p);
  25. printf("*(p+0)=%d\\n",*(p+0));
  26. printf("*(p+1)=%d\\n",*(p+1));
  27. system("pause");
  28. }
 
练习 :学生学号管理系统
提示用户输入学生的人数 根据输入申请堆内存 用来保存学生的学号
提示用户输入学生的学号
来了插班生 申请新的内存用来保存新来学生的学号
提示用户输入新来学生的学号
回显所有学生的学号
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. //realloc re- alloc 在malloc函数的基础上 重新分配足够大的内存
  4. // realloc(malloc的返回值,一共要的申请内存大小) 返回申请到的足够大的内存首地址
  5. // 如果malloc 申请到的内存 后面还有足够大的空间供使用 这个时候 直接在malloc申请到的内存后 继续申请足够大的内存
  6. // 如果malloc 申请到的内存 后面没有足够大的空间供使用 这个时候 会开辟一块新的足够大的内存 并且把之前malloc 申请到的内存的
  7. //内容复制过来 释放之前malloc的内存
  8. main(){
  9. printf("请输入学生的人数:");
  10. int count;
  11. scanf("%d",&count);
  12. //申请足够大的堆内存 用来保存学生的学号
  13. int* p = malloc(sizeof(int)*count);
  14. int i;
  15. for(i = 0;i<count;i++){
  16. printf("请输入第%d个学生的学号:",(i+1));
  17. scanf("%d",p+i);
  18. }
  19. for(i = 0;i<count;i++){
  20. printf("第%d个学生的学号是%d\\n",(i+1),*(p+i));
  21. }
  22. //来了插班生
  23. printf("请输入插班生的人数:");
  24. int newcomer;
  25. scanf("%d",&newcomer);
  26. //申请新的足够大的内存
  27. p = realloc(p,(newcomer+count)*sizeof(int));
  28. for(i = count;i<count+newcomer;i++){
  29. printf("请输入第%d个学生的学号:",(i+1));
  30. scanf("%d",p+i);
  31. }
  32. for(i = 0;i<count+newcomer;i++){
  33. printf("第%d个学生的学号是%d\\n",(i+1),*(p+i));
  34. }
  35. system("pause");
  36. }
 
 
11.C的结构体 ☆☆☆☆☆
class Student{
 char gender;
   short age;
   int score;
}
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. /*
  4. class Student{
  5. char gender;
  6. short age;
  7. int score;
  8. void study(){
  9. System.out.println("好好学习");
  10. }
  11. }
  12. Student stu = new Student();
  13. stu.age;
  14. */
  15. struct Student{
  16. char gender; //1
  17. short age; //2
  18. int score; //4
  19. void(*study)();
  20. };
  21. void study(){
  22. printf("good good study,day day up!!!\\n");
  23. }
  24. //函数指针的定义 返回值(*函数指针的名字)(形参类型)
  25. //结构体的大小 ① 大于或者等于所有成员的大小的和 ②是最大的成员的大小的整数倍
  26. //C结构体中只能有变量的声明 不能有函数 可以通过函数指针 让一个函数指针变量指向一个具体的函数 使结构体实现有函数的功能
  27. //结构体的指针
  28. main(){
  29. struct Student stu = {‘f‘,18,90,&study};
  30. //让学生study指针变量指向具体函数 需要注意指向的这个函数 返回值和形参得跟函数指针保持一致
  31. //stu.study = &study;
  32. stu.study();
  33. printf("学生的性别是%c\\n",stu.gender);
  34. printf("学生的年龄是%hd\\n",stu.age);
  35. //printf("学生的成绩是%d\\n",stu.score);
  36. printf("学生结构体占%d个字节\\n",sizeof(stu));
  37. struct Student* p = &stu;
  38. (*p).study();
  39. //间接引用运算符
  40. p->study();
  41. struct Student** p2 = &p;
  42. (**p2).study();
  43. (*p2)->study();
  44. system("pause");
  45. }
 
12.C的联合体
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. union un{
  4. short s;
  5. int i;
  6. }
  7. // ①联合体所有的成员 使用同一块内存
  8. //② 联合体的大小取决于最大的变量占的内存空间
  9. //③对联合体中的成员多次赋值 只有最后一次是有意义的 之前的赋值都会被覆盖
  10. main(){
  11. union un u;
  12. printf("union联合体占%d个字节\\n",sizeof u);
  13. u.s = 1234;
  14. u.i = 12345678;
  15. printf("u.s = %hd\\n",u.s);
  16. system("pause");
  17. }
 
13.C的枚举
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. enum Weekday{
  4. SUN,MON,TUE,WEND,THUR,FRI=8,SAT
  5. }
  6. //枚举 定义了当前类型的取值范围只能从枚举值中取值
  7. //默认枚举值从0开始 后面依次+1
  8. main(){
  9. enum Weekday day = SAT;
  10. printf("day = %d\\n",day);
  11. system("pause");
  12. }
 
14.typedef 自定义类型

以上是关于JNI_01的主要内容,如果未能解决你的问题,请参考以下文章

JNI_01

Android JNI 打印 int64_t 到文件

Android的JNI调用

JNI_2

在 Brother SDK 上的应用程序中检测到 JNI 错误

Android - JNI // NDK无法找到SIGSEV