JNI开发系列之C语言

本文介绍了JNI的概念及其在Java中的应用价值,同时深入探讨了C语言的基础知识,包括数据类型、输入输出函数、指针等内容。

JNI开发系列之C语言

什么是JNI

  • JNI全称Java native interface
  • JNI可以看作是翻译,实际上就是一套协议、接口

为什么要使用JNI?

  1. Java的特点是一处编译到处运行,即跨平台
  2. Java运行在虚拟机上,JNI可以扩展Java虚拟机的能力,让Java代码可以调用驱动
  3. Java是解释型语言,运行效率相对较低,C/C++的效率要高很多,通过JNI把耗时、好性能的操作放在C/C++可以提高Java运行效率
  4. Java代码编译成的.class文件安全性较差,可以通过JNI把重要的业务逻辑放到C/C++去实现,C/C++反编译比较困难,安全性较高
  5. C历史悠久1972年就诞生了,在这几十年已经有了现成的优秀C库,比如FFMPEG、OpenGL等等,我们可以使用JNI来调用这些库,而没必要再重复造轮子。

怎么使用JNI

  • 学习C、C++语法
  • 学习JNI开发流程
  • 学习使用NDK开发工具,在Android Studio已经推荐使用CMake了

C的基本语法

  • 第一个C语言程序,Hello World
#include<stdio.h>   //include相当于Java的import,stdio.h标准的输入输出(standard io) 
#include<stdlib.h>  //stdlib.h标准函数库,相当于Java的com.java.lang 

main() {
    printf("Hello World\n");    //相当于System.out.println("Hello World"); 
    system("pause");            //system执行Windows系统命令,表示暂停。比如在CMD中执行notepad一样。 
} 
  1. Java的基本数据类型:
    byte(1)、char(2)、short(2)、int(4)、long(8)、float(4)、double(8)、boolean(1)
  2. C的基本数据类型:
    char(1)、short(2)、int(4)、long(4)、float(4)、double(8)、signed(表示正负)、unsigned(只能是正数)、void。

    • signed和unsigned只能用来修饰整型变量,占用大小随整型类型走。
    • 没有boolean和byte类型,其中boolean用0表示false,用非0表示true。

    需要注意的是不同编译器所占用字节也不一样,没必要去死抠,知道这么回事就可以了。

#include<stdio.h>   //include相当于Java的import,stdio.h标准的输入输出(standard io) 
#include<stdlib.h>  //stdlib.h标准函数库,相当于Java的com.java.lang 

/**
C语言中的基本数据类型:char(1)、short(2)、int(4)、long(4)、float(4)、double(8)、signed、unsigned(占用大小随整型类型走) 
*/ 
main() {
    char c = 'a'; 
    printf("char占用%d个字节\n", sizeof(c));

    short s = 12;
    printf("short占用%d个字节\n", sizeof(s));

    int i = 12345;
    printf("int占用%d个字节\n", sizeof(i)); 

    long phone = 18672;
    printf("long%d字节\n", sizeof(phone));

    float price = 3.14; 
    printf("float占用%d个字节\n", sizeof(price));

    double PI = 3.1416926;
    printf("double占用%d个字节\n", sizeof(PI));

    signed ss = -100;
    printf("signed占用%d字节\n", sizeof(ss));

    signed char unss = -99;
    printf("%d\n", unss);
    printf("unsigned占用%d字节\n", sizeof(unss));

    system("pause");
} 

C的输出函数

#include<stdio.h>   //include相当于Java的import,stdio.h标准的输入输出(standard io) 
#include<stdlib.h>  //stdlib.h标准函数库,相当于Java的com.java.lang 

/**
printf("输出的内容[格式化符号]", 变量);

%d      -->     int
%ld     -->     long
%lld    -->     long long
%hd     -->     short
%c      -->     char
%f      -->     float,默认输出的是6位长度的小数,不够补0,超出的四舍五入。想手动指定加上.X,如%.4f表示4位的小数 
%lf     -->     double,默认输出的是6位长度的小数,不够补0,超出的四舍五入。想手动指定加上.X,如%.8f表示4位的小数 
%u      -->     unsigned 
%x[X]   -->     十六进制输出int、long int或者short,为了区分可以在前面加上前缀,如%#x 
%o      -->     八进制输出int、long、short
%s      -->     字符串(注意没有字符串类型) 
*/
main() {
    char c = 'z';
    short s = 123;
    int i = 12346;
    long l = 1234567;
    float f = 1.2346789;
    double d = 3.1415926;

    printf("c = %c\n", c);
    printf("s = %hd\n", s);
    printf("i = %d\n", i);
    printf("l = %ld\n", l);
    printf("f = %f\n", f);
    printf("f = %.4f\n", f);
    printf("d = %lf\n", d);
    printf("d = %.9lf\n", d);

    printf("十六进制的输出i:%x\n", i); 
    printf("十六进制的输出i,带前缀的:%#x\n", i); 
    printf("八进制的输出s:%o\n", s); 
    printf("八进制的输出s,带前缀的:%#o\n", s); 

    //字符串其实就是字符数组
    char charArray[] = {'a', 'b', 'c', 'd', '\0'};  //C语言中字符串必须加上结束符\0,这样它就能识别结束,否则无法正常输出
    printf("charArray的输出:%s\n", charArray); 
    char str[] = "这是我写的Hello World";    //这种是自带结束符的,并且是可以有非英文字符,上面是不可以的
    printf("str的输出是:%s\n", str); 
    system("pause");            //system执行Windows系统命令,表示暂停。比如在CMD中执行notepad一样。 
} 

C的输入函数

#include<stdio.h>
#include<stdlib.h>

/**
C语言的输入输出函数:

printf输出函数

scanf输入函数 

*/ 
main() {
    printf("请输入你的年龄:\n");
    int age;
    scanf("%d", &age);  //&表示取地址符 
    printf("您的年龄是:%d\n", age);
    printf("age的内存地址%d,占用内存大小:%d\n\n", &age, sizeof(age)); 

    //输入字符串
    char charArray[4];
    //注意C的数组是不检测越界问题,你输入多少就能接收多少,因此建议合理使用大小 
    printf("请输入姓名:\n");
    scanf("%s", &charArray);
    printf("您的姓名是:%s\n", charArray); 
    printf("charArray的内存地址%d,占用的内存大小:%d\n\n", &charArray, sizeof(charArray));

    printf("您的年龄是%d,您的姓名是%s",  age, charArray); 

    /*
    请输入你的年龄:
    12
    您的年龄是:12
    age的内存地址6487628,占用内存大小:4

    请输入姓名:
    555
    您的姓名是:555
    charArray的内存地址6487616,占用的内存大小:4

    您的年龄是12,您的姓名是555    
    --------------------------------

    需要注意的是charArray的内存地址是6487616,而age的内存地址是6487628,中间相差12个字节。在这里我有点奇怪的是为啥是12个字节,我的系统是64位的。那么这里其实牵扯到一个问题,就是如果charArray的输入超过了12字节(即12个字符)那么你会发现输出的age值不是你最开始输入的值。原因是因为charArray所输入的字符地址超过了范围,这就造成后面变量的值就被改写了,说白了就是数组越界了,因此我们应该合理的 使用数组大小,比如下面的结果我输入了12个字符(abcdefghijkl)加一个'\0'字符就是13个字符,已经超出了12个字节了,其age的输出结果是0:

    请输入你的年龄:
    15
    您的年龄是:15
    age的内存地址6487628,占用内存大小:4

    请输入姓名:
    abcdefghijkl
    您的姓名是:abcdefghijkl 
    charArray的内存地址6487616,占用的内存大小:4

    您的年龄是0,您的姓名是abcdefghijkl
    */ 
}

内存地址的概念

CPU主要有3个总线来控制着:
1. 地址总线:标识地址,地址总线的大小表示能支持多大的内存,如32系统最大支持2^32个byte即4G内存
2. 数据总线:传输数据,比如3.14
3. 控制总线:读写操作,写一个数据或读一个文件

指针

我们一般说的指针其实是指针变量,而指针变量只能用来保存变量的地址。

#include<stdio.h>
#include<stdlib.h>

main() {
    int num = 123;
    //一般计算机使用16进制来表示内存地址
    printf("num的值:%d,num的内存地址:%#x\n", num, &num); 

    /*
    1、* pointer表示是int类型的指针变量,指针类型的变量只能用来存放内存地址。
    2、使用&符号,可以获取变量的地址。
    3、把&num赋给指针变量表示指针变量指向了num的地址 
    */
    int *pointer = &num;
    printf("pointer的值:%#x\n", pointer); 

    //使用* pointer可以获取该地址所存放的值 
    int value = *pointer;
    printf("value的值:%d\n", value);

    *pointer = 99; 
    printf("对指针变量修改值,那么num的值:%d\n", num);
} 
  1. 需要注意的是C语言中是不允许修改没有赋值(即没有初始化)的指针变量的值,否则就崩溃。这种没有赋值的指针称之为野指针,原因是野指针可能是内存中某一块地址,如果自己没有初始化的话直接赋值可能会出现问题,因此系统不允许你这么做。
int *age;
printf("指针变量age的地址:%#x\n", age);

//对野指针(没有初始化)进行赋值会崩溃 
*age = 666;
  1. 指针变量只允许指向同类型的变量,比如int类型的指针变量只允许指向int类型的变量,否则会错误。
double pi = 3.14;
/*
不过我是用Dev-C++来编译的时候过不去,提示“cannot convert 'double*' to 'int*' in initialization”
*/
int *number = &pi;
printf("*number的值:%d\n", *number);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

养-乐多

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值