C、C++、Java?Java Native Interface(JNI)特辑——从C语言开始
JNI简介
一些基本概念和介绍我就不重复了,百度讲的比我好。简单来说就是通过java的native关键字声明的方法调用对应的C/C++实现的函数。其中的优劣很多,比如提升了效率却丧失了程序的跨平台性、能够直接与硬件驱动进行交互却增加了java与C/C++代码的耦合性......
C语言的简单回顾
1.java基本数据类型(字节) 2.C的基本数据类型(字节)
boolean 1 null
byte 1 null
char 2 char 1
short 2 short 2
int 4 int 4
long 8 long 4
float 4 float 4
double 8 double 8
char, int, float, double, long, short, signed, unsigned, void
1. signed 有符号数 最高位是符号位 可以表示负数 但是表示的最大值相对要小。
2.unsigned 无符号数 最高位是数值位 不可以表示负数 表示的最大值相对要大。
3. signed unsigned 只能用来修饰整形变量 char short int long。
4.C没有 boolean byte C用0和非0表示false true。
C的输出函数:
%d - int
%ld – long int
%lld - long long
%hd – 短整型
%c - char
%f - float
%lf – double
%u – 无符号数
%x – 十六进制输出 int 或者long int 或者short int
%o - 八进制输出
%s – 字符串
1.占位符不要乱用 要选择正确的对应类型否则可能会损失精度。
2. C没有String类型 C的字符串实际就是字符数组。
3.C数组定义 [ ]只能再变量名之后。
4.C字符串两种定义方式。
5.char str[] = {'h','e','l','l','o','\0'};//注意'\0'字符串结束符。
6.char str[] = "你好"; //这种定义方式不用写结束符 可以表示汉字。
C的输入函数
1.scanf("占位符", &地址);
2.& 取地址符
3.C字符串不检查下标越界 使用时要注意
内存地址的概念
1.声明一个变量,就会立即为这个变量申请内存,一定会有一个对应的内存地址。
2.没有地址的内存是无法使用的。
3.内存的每一个字节都有一个对应的地址。
4.内存地址用一个16进制数来表示。
5.32位操作系统最大可以支持4G内存。
6.32位系统的地址总线为32位,也就是说系统有2^32个数字可以分配给内存作为地址使用。
1.指针入门
int i = 123;
//一般计算机中用16进制数来表示一个内存地址
printf("%#x\n",&i);
//int* int类型的指针变量 pointer指针 指针变量只能用来保存内存地址
//用取地址符&i 把变量i的地址取出来 用指针变量pointer 保存了起来
//此时我们可以说 指针pointer指向了 i的地址
int* pointer = &i;
printf("pointer的值 = %#x\n",pointer);
printf("*pointer的值%d\n",*pointer);
*pointer = 456;
printf("i的值是%d\n",i);
system("pause");
2.指针常见错误
1)声明了指针变量后 未初始化直接通过*p 进行赋值操作 运行时会报错。
2)未赋值的指针称为野指针。
3)指针类型错误 如int* p 指向了double类型的地址, 通过指针进行读取操作时,读取值会出错。
指针深入
1.值传递和引用传递(交换两个数的值)。
1)引用传递本质是把地址传递过去。
2)所有传递其实本质都是值传递,引用传递其实也是传递一个值,但是这个值是一个内存地址。
void swap(int* p, int* p2){
int temp = *p;
*p = *p2;
*p2 = temp;
}
main(){
int i = 123;
int j = 456;
//将i, j的地址传递过去
swap(&i,&j);
printf("i = %d, j = %d", i, j);
}
2.返回多个值
1)把地址作为参数传入函数中,当函数执行完毕时,参数的值就已经被修改了。
多级指针
1.int* p; int 类型的一级指针 int** p2; int 类型的二级指针 。
2.二级指针变量只能保存一级指针变量的地址。
3.有几个* 就是几级指针 int*** 三级指针。
4.通过int类型三级指针 操作int类型变量的值 ***p。
int i = 123;
//int类型一级指针
int* p = &i;
//int 类型 二级指针 二级指针只能保存一级指针的地址
int** p2 = &p;
//int 类型 三级指针 三级指针只能保存二级指针的地址
int*** p3 = &p2;
//通过p3 取出 i的值
printf("***p3 = %d\n", ***p3);
1数组和指针的关系
1)数组占用的内存空间是连续的。
2) 数组变量保存的是第0个元素地址,也就是首地址。
3)*(p + 1):指针位移一个单位,一个单位是多少个字节,取决于指针的类型。
4)不管变量的类型是什么,它的内存地址的长度一定是相同的。
5)类型不同只决定变量占用的内存空间不同。
6)32位环境下,内存地址长度都是4个字节,所以指针变量长度只需4个字节即可。
7)区分指针类型是为了指针位移运算方便。
2.堆栈概念 静态内存分配 动态内存分配
1)栈内存。
2)系统自动分配。
3)系统自动销毁。
4)连续的内存区域。
5)向低地址扩展。
6)大小固定。
7)栈上分配的内存称为静态内存 。
9)静态内存分配。
10)子函数执行完,子函数中的所有局部变量都会被销毁,内存释放,但内存地址不可能被销毁,只是地址上的值没了。
11)堆内存。
12)程序员手动分配。
java:new
c:malloc
13)空间不连续。
14)大小取决于系统的虚拟内存。
15)C:程序员手动回收free。
16)java:自动回收。
17)堆上分配的内存称为动态内存。
结构体
struct name{
//函数指针
jint (*GetVersion)(int*);
}
1)结构体中的属性长度会被自动补齐,这是为了方便指针位移运算。
2) 结构体中不能定义函数,可以定义函数指针。
3)程序运行时,函数也是保存在内存中的,也有一个地址。
4)结构体中只能定义变量。
5)函数指针其实也是变量,它是指针变量。
6)函数指针的定义 返回值类型(*变量名)(接收的参数);。
7)函数指针的赋值: 函数指针只能指向跟它返回值和接收的参数相同的函数。
8)调用结构体函数:(一级指针)->函数名(形参);
联合体
union u{
int num; //4
double d; //8
}
1)长度等于联合体中定义的变量当中最长的那个。
2) 联合体只能保存一个变量的值。
3)联合体共用同一块内存。
自定义类型typedef
1)typedef可以看作type define的缩写,顾名思义就是类型定义,也就是说它只是给已有的类型重新定义了一个方便使用的别名,并没有产生新的数据类型。
2)
1.简单的定义变量的别名。
typedef char * PChar;
PChar a, b; //相当于char *a; char *b;
2.与结构体的结合使用。
typedef struct Node{
int a;
char *b;
}*PNode;
PNode a, b;
void指针
1)可以指向任意类型的数据,亦即可用任意数据类型的指针对void指针赋值。
int * pint;
void *pvoid;
pvoid = pint; /* 不过不能 pint= pvoid; */
如果要将pvoid赋给其他类型指针,则需要强制类型转换如:pint= (int *)pvoid;
至此我们把C语言的基本概念回顾了一边,但是只是抛砖引玉的作用,可以有针对的去详细复习。下篇我们开始正式聊聊JNI。
欢迎长按下图-识别图中二维码或者扫一扫,搜索微信公众号:黄君华。关注我的公众号:
如果你有不同意见或建议或者有好的技术文章想和大家分享欢迎投稿,可以把你的文章使用附件的形式发送到我的邮箱2908116133@qq.com
谢谢阅读!