Android高级-NDK-C/C++基础篇

1:函数:

2:函数定义

在程序中测试一下;

C语言执行是从上而下执行。是由函数组成的可执行文件。

C是以函数为基础,而java是以类为基础,类作为一个对象,方法可以写在类中。

而C是函数组成的,当我们设计一个程序,会产生很高的耦合,而头文件就相当于一个接口,每一个接口,每一个类都有一个接口,如果我想调用这个类,可以直接把这个接口,即.h文件引入进来就可以了,不用引入.cpp文件。

实际上,接口只是对类进行规范,在编译的时候,并不会被编译成具体的对象;

同样的,.h头像并不会参与编译,真正的是头文件所实现的c文件。是为了解决程序的耦合问题

3:指针函数

 

指针函数的写法,和我们平时的写法是一致的。

至于指针类型是什么,我们不需要担心,可以是int类型,也可以是Object类型,也可以是void类型

所以当我们&(取地址),这里的void类比于object类型

4,函数指针

定义:函数指针是指向函数的指针变量,即本质是一个指针变量。

如:

   int(*f)(int x); /*声明一个函数指针**/

    //前面代表函数的返回值类型

   func;   //将func函数的首地址赋值给指针f/

void(*funcp)();
	
 void point_func() {
	 printf("函数指针\n");
}

int main()
{
	int a = 2;
	int_add_func(&a);
	
	funcp = point_func;
	funcp();

}

运行正常打印。

java面向对象,对基本数据类型可以修改,通过指针可以修改

5:Linux内存布局原理

基础知识 目录框架~

1:C和C++基础

2:MakeFile与Cmake详解

3:Opencv图像识别

4:网易音视频编解码

5:阿里Sophix实战==热修复

6:网易课堂直播核心技术(Ffmpeg,Rtmp)

7:网易直播通话实战(Webrtc)

Android瓶颈:

Ndk还能继续深入研究

只学习java是不够的~

 

C语言最难的地方

内存   指针  

本节课学习内容

1:数据类型

2:数组

3:内存布局

4:物理内存

5:虚拟内存

1:内存定义

硬件角度:内存是计算机必不可少的一个组成部分,是于CPU沟通的桥梁,计算机中所有的程序都是运行在内存汇中的。

譬如:是内存条

逻辑角度:内存是一块具备随机访问能力,支持读,写操作,用来存放程序以及程序运行中产生的数据区域。

譬如:我们可以把建筑物当做一个内存,每一个内存都对应一个房间

,整个内存条就对应这栋大楼,每个内存地址对应房间号,内存中储存的内容就是房间里面住的人,我们可以根据内存的单元地址,我们可以根据地址找到存储内容

关于内存还有很多概念:

比如内存单位,内存编制,内存地址,内存组成,基础函数。

内存单位:内存都是有大小的

类型:1:位  bit 是电子计算机中最小的数据单位,每一位的状态只能是0 或者1

           2:字节: 1Byte = 8bit  是内存基本的计量单位

           3:KB:     1KB = 1024Byte   1KB = 1024 * 8 = 8192 bit

           4    MB     1MB =1024 KB 类似的还有GB,TB

内存编制:计算机中的内存按字节编址,每个地址中的存储单元可以存放一个字节(8bit)的数据,CPU通过内存地址获取指令和数据,并不关心这个地址所代表的空间具体再什么位置,怎么分布,因为硬件的设计保证一个地址对应一个固定的空间,所以说:内存地址和地址指向的空间共同构成了一个内存单元。

   譬如:一个建筑立面有地板砖

内存地址:内存地址通常用十六进制的数据表示,指向内存中的某一块区域。

          java中不需要我们来管理内存地址,但是C语言就需要我们自己来管理了。

内存地址分配规则

内存分配规则是连续的,一个挨着一个的。

例如村子里面的房子都是一个挨着一个的,当有新的对象产生的时候,会给分配一个新的地址。

当对象申请内存的时候,先给对象分配一个编码,这个编码就是内存地址。

 

比如上面的0x0ffc2  就是一个地址,至于这个地址存放在哪,不确定,但是可以通过这个地址找到具体的对象。

内存对象

指针指向的内存区域能存储不同的类型。

基本数据类型

内存组成;

我们先来看android的内存组成:

而C语言的内存组成:

c语言的执行不依赖于任何虚拟机,直接编译成汇编语言直接执行。

BSS端:存放成员变量,在编译的时候无法确定大小

数据端:存放的是数据

代码端:把这个函数转化成汇编语言。

基于汇编语言形成的过程语言。

下面学习:数组和指针,数组指针,指针数组

1:数组:是数据集合,在内存中是连续的

通过指针操作数组

int main()
{
	int arry[] = { 100,200,300 };
	for (int i = 0; i < 3; i++) {
	
		printf("数组 %d\n" , arry[i]);
	}
	int* p = arry;

	*p = 400;
	for (int i = 0; i < 3; i++) {

		printf("数组 %d\n", arry[i]);
	}

	return 0;
}

打印的值是

发现指针修改的是数组的第一个元素进行了修改;

那么如何指向第二个元素呢?

int main()
{
	int arry[] = { 100,200,300 };
	for (int i = 0; i < 3; i++) {
	
		printf("数组 %d\n" , arry[i]);
	}
	int* p = arry;

	*(p+1) = 400;
	for (int i = 0; i < 3; i++) {

		printf("数组 %d\n", arry[i]);
	}

	return 0;
}

第二个数组元素变成了400;

+1的操作, 

当前的指针类型是int类型,那么+1就是+了4个字节

指针意义:

通过指针可以操作数组的能力

2:指针数组

这个数组中的每一个元素都是一个指针,指针变量分别指向不同的变量abc;

如图:

int main()
{
	int arry[] = { 100,200,300 };
	int *pa[3];//指针数组

	for (int i = 0; i < 3; i++) {
	
		pa[i] = &arry[i];
	;
	}
	
	for (int i = 0; i < 3; i++) {

		printf("数组 %d\n", pa[i]);
		printf("数组 %d\n", *pa[i]);
	}

	return 0;
}

 

3:指针优先级

定义:() > []  > *

意思就是定义指针数组的时候

int *pa[3];//指针数组

先定义pa[3]为数组,后面才取* 为指针,所以为指针数组。

4:数组指针(也称为行指针)

定义  int (*p)[n]

优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n.也可以说是p的步长。

也就是说执行p+1时,p要跨过n整个整型数据的长度。

int a[3][4];

int (*p)[4]//该语句定义一个数组指针,指向含4个元素的一维数组

p=a;//将该二维数组的首地址赋值给p,也就是a[0]或&a[0][0]

p++;//该语句执行过后,也就是p= p +1 ,p跨过行a[0]指向了a[1]

然后我们一起来看一下指针数组 和数组指针的区别

写法上就是多了一个括号

指针数组,他是一个数组,这个数组里面存放的是指针  int *p[n]

而数组指针,只是一个变量,这个变量存放一个指针    int (*p)[n]

但是他的步长发生了变化,他的步长指向的是二维数组的首地址,如果你对当前指针进行

+1操作,那就会指向第二行的首地址

5:结构体

基础知识:

结构体和共用体是一致的。

struct关键字类比于java中的class 

student ,a 是成员变量  

例如:


struct Student {

	int i;
	short j;
}s1, s2;

int main()
{
	struct Student student;
	student.i = 10;
	student.j = 20;
	printf("使用结构体打印变量 %d \n", sizeof(student));
	s1.i = 8;
	s2.j = 6;
	printf("使用结构体打印变量 %d \n", sizeof(student));

	return 0;
}

运行结果

结构体打印是8 ,为什么是8呢 我们来学习一下c的内存对齐

6:内存对齐

定义:对齐跟数据再内存中的位置有关系。如果一个变量的内存地址正好位于它长度的整数倍,他就被称作自然对齐。

      比如在32位cpu下,假设一个整型变量的地址为0x0000004,那么他就是自然对齐的。32位就是4位

     当结构体需要内存过大,使用动态内存申请。结构体占用字节数和结构体内字段有关系。指针占用内存就是4/8字节,因此传       指针比传值效率更高。

 

结构体存储原则:

1 ,结构体变量中的成员的偏移量必须是成员大小的整数倍(0被让认为是任何数的整数倍)

2,结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公数倍。

例如:刚才定义了 short类型,他是2个字节,在32位cpu下,他最小的单位步长是4个字节,2个字节小于4个字节,所以他会给一个short类型的成员变量分配4个字节,只不过后面2个自己个是不起作用的。

为什么要内存对齐呢?

例如:小张想找隔壁老忘和老宋一起帮忙照看下媳妇

          由于他们住在不同的楼层,所以小张必须要跑两次。

                            

这个是没有内存对齐的情况下,小张必须跑两次,那么小张可以不可以跑一次呢/

那就只能让老张和老王同时在一个房间。 (放到一起就是结构体。。。。)

char也是占1个字节

对齐前,找到一个变量,需要两次寻址,比如int i  在储存过程中换行了

对齐后是12个自己   前面c1是1个字节,后面是4个字节,c2也是1个字节  但是对齐后 就占了12个字节

7:共用体

共用体和结构体类似

也是一个数据类型的结合。

定义:共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。

您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值

共用体提供了一种使用相同的内存位置的有效方式。

例如:

我有100个成员变量,但是在某一时刻只有一个变量有值,那么此时用共用体就非常省内存。

使用:

注意:共用体占用的内存应足够存储共用体中最大的成员。例如,上面的实例中,Data占用了20个字节的内存空间,因为再各个成员中,字符串所占用的空间是最大的。下面的实例将显示上面的共用体占用的内存大小。

取决于最长的内存大小

union MyUnion
{
	int i;
	float j;

};

int main()
{
	union  MyUnion mystudent;

	mystudent.i = 10;
	mystudent.j = 11;

	printf("i的地址 %#x\n",&mystudent.i);
	printf("j的地址 %#x\n", &mystudent.j);

	return 0;
}

运行结果:

 

union MyUnion
{
	int i;
	int k;
	float j;
};


int main()
{
	union  MyUnion mystudent;

	mystudent.i = 10;
	printf("i的地址 %d\n", mystudent.i);
	mystudent.j = 11;
	mystudent.k = 11;
	printf("i的地址%d\n",mystudent.i);
	printf("j的地址 %d\n", mystudent.j);

	return 0;
}

运行结果:

将i值的内存位置重新赋值给k值。

8:so动态库与编译

库的概念:

windows平台和linux平台下都大量存在着库。android中也存在着库,库顾名思义,值的是一个容器文件,里面装的都是函数,

由于Windows和linux的平台不同(主要是编译器、汇编器和连接器的不同),一次二者的二进制库是不兼容的。

库存在的意义:

库是被人写好的现有的,成熟的,可以复用的代码,现实中每个程序都要依赖很多基础的底层库。UK额能每个人的代码都是从零开始的,因此库的存在意义非同寻常。

库的种类:

动态库和静态库

.so/.dll   和  .a/.lib

可以把库理解为jar包

他们的区别是发生在链接和加载过程中的,目的都是加载第三方的函数

如何编译一个动态库?

使用gcc进行预编译和编译。

//======================

 

 

//=====================

动态库和静态库区别;

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值