[C++系列] UNIX高级编程 动态库使用 指针 别名 gdb调试器的使用
in C/C++ with 0 comment

[C++系列] UNIX高级编程 动态库使用 指针 别名 gdb调试器的使用

in C/C++ with 0 comment

复习:
一,大型软件的组织
二,静态库的制作与使用
三,环境变量
四,动态库的制作和使用

一,动态库的使用

二,指针

三,使用typedef定义类型

四,gdb调试器的使用

动态库的使用

链接使用静态库和动态库的区别:

* 使用静态库是在编译链接成可执行文件的时候,做的实际链接’
* 使用静态库生成的可执行文件,不再依赖于静态库。
* 

* 使用动态库是在编译链接成可执行文件的时候,做的虚拟链接。实际链接发生在可执行程序加载的时候。
* 使用动态库生成的可执行文件,依然依赖于动态库。
* 可执行文件不用更新,但是可执行文件依赖的动态库做更新,这样做可以改变或增加可执行文件的功能。
    可以通过改变借口的功能,扩充可执行文件的功能。

静态链接与动态链接的区别

     ios       完全采用的上述思想

复习指针

指针和C语言知识的融合。

* 分清常量和变量
* 
    * 不管那个量,都占用内存空间。

* 常量占用的内存空间的值是不能改变的。r
* 变量占用的内存空间的值是可以改变的。rw

首先通过变量的名字找到变量的地址,然后通过地址找到数据,取出数据里的内容。

数据类型 :

* 什么是数据类型?
* 
    * 类型可以理解为访问变量的空间时的访问方式。
    * Int 4.  Float 4 内存中数据结合的方式。

* 数据类型:
* 运算符的优先级及其结核性
* 变量的作用域和生命周期

数据类型 与 指针:

Int   char.   Float.  Bouble.   Void    *

4
*p p是指针类型的变量,p占用内存空间,4 有自己的地址,有自己的空间。p的空间里存放指针类型值。
地址是指针的一个实例。
找到数据类型

练习:

Int p;
Int *p;
Int **p;

Int arr[3];

数组是类型。
Arr是数组的名字。数组的名字就是数组的首地址。
有3个元素,每个元素的类型都是int类型。
一共占用12个字节的内存空间。这12个字节的内存空间是连续的。

int *p[3];
指针数组还是数组指针
P是数组的名字。这个数组里有三个元素,每个元素都是指针类型的。

Int arr[2][3];
同一个地址,使用不同的访问方式会得到不同的结果。
Arr是数组的名字,有2个元素。arr[0], arr[1]。元素的类型是int[3]类型。
Arr[0]是数组的名族,有3个元素,每个元素是整形的。
arr+1 int[3]
Arr[0]+1 int

Int (*p)[3];
P是指针类型的变量。要找出数据类型?
int[3]是数据类型。
p+1;1代表12个字节。
上述叫做数组指针。

Void *malloc(size_t,size);
返回值是地址的函数。void的意思是对内存的空间不访问 。

Void (*p)(void)
P是指针类型变量。 数据类型 void (void)
函数的名字就是函数的入口地址。

Int.  (*func_t)(int,int)
Func_t。指针类型的变量,
int (int,int)   数据类型。
int (*p[4])(int,int);

*P[4]. P是数组的名字 ,这个数组里有4个元素,每个元素都是指针类型的。

struct. Node{
        Int num;
        struct. Node *next;

}
Int p;
Int *p;
Int **p;
Int *p[3];
Int (*p)[3];
Void *malloc(int,int);
Int (*p)(int,int);
Int(*p[4])(int,int);

使用typedef定义类型

使用typedef为类型定义别名

为了程序的可读性需要为类型定义别名。

typedef使用三个步骤

1,定义类型的变量或者常量。 Int count_t;
2,在第一步的前边加上typedef。 变量的名字就是原来类型的别名。如:typedef int count_t; count_t 就是int 的别名。
3,使用别名定义变量。count_t c;

举例:

1,char *str_t;
Str_t 是变量
Typedef char *str_t;
Str_t. St1,st2;======char *str1,*str2;
2,struct. Node{
        Int num;
        Struct node  *next;
} node_t;
Struct node test;
Node_t test;

Node_t是一种类型(节点类型)

Node_t. *node_p;
Node_p    h;
Node_t *q;

3,int arr_t[3];

Typedef int arr_t[3];
Arr_t
int[3];

Arr_t   a;
Arr_t  b[2];b是数组的名字。数组里有两个元素,每个元素都是arr_t类型的。是一位数组类型的。


char Arr[3];
*arr
Arr
*arr+2
*(arr+2)+2

举例严重:

4,int(*f_t)(int,int);

Typedef int (*f_t)(int,int);
f_t, f;

Int (*p)[3];
Typedef  int  (*p_t)[3];

P_t a;

补充:

大端和小端
高位字节放到低地址大端。 网络字节序
高位地址放在高地址小端 主机字节序一般小端。

作业: 编写代码实现判断主机字节序。

回调函数

只要是有类型的变量就可以作为函数的参数。
指针类型的变量就可以作为函数的参数。
int(*f)(int,int);
把函数作为另一个函数的参数传递出去,这样的函数叫做回调函数。

举例。 回调函数:

gdb调试器的使用

Gcc bash. Makefile. gdb

使用gdb调试步骤
1,在编译链接生成可执行文件的时候,加-g/-ggdb参数。
生成的可执行程序带有调试信息。
2,使用gdb调试可执行程序
Gdb a.out
调试器命令

L. list。列出程序的源代码
b 【函数名或者行号】 breakpoint。在函数或行号处设置断点
r run。 运行程序,到断点处停下。
n next 执行一条语句
P 变量或常量名。print 输出变量的值
s step 下一步。 切换到函数中执行
q quit 退出

总结:
一,动态库的使用
二,C指针
三,typedef定义别名
四,gdb调试器的使用

作业:
大端小端
400。


复习:

一、大型软件的组织
二、静态库的制作和使用
三、环境变量
四、动态库的制作和使用

今天的内容:
一、动态库的使用(续)
链接使用静态库和动态库的区别
使用静态库是在编译链接成可执行文件的时候,做的实际链接。
使用静态库生成的可执行文件,不再依赖于静态库。

使用动态库是在编译链接成可执行文件的时候,做的虚拟链接。实际链接发生在可执行程序加载的时候。
使用动态库生成的可执行文件,仍然依赖于动态库。

可执行文件不用更新,但是可执行文件依赖的动态库做更新,这样可以改变或增加可执行文件的功能。
pmath文件夹的文件为例,进行演示。
a.out是不是就是一个框架。可以通过改变接口的功能,扩充a.out的功能。

静态链接 动态链接的区别
ios 完全采用刚才的思想
懒人思想

二、复习C语言指针
和很多人谈到C语言的时候,都说指针最重要。老王不赞成。
指针和C语言知识的融合。
1、常量和变量
不管是哪个量?都占用内存空间。
常量占用的内存空间里的值是不能改变的。r
变量占用的内存空间里的值是可以改变的。rw

5==0000,0101
321 ==0000,0001,0100,0001
首先通过变量的名字找到变量的地址,然后取出地址里的内容。

什么是数据类型?
数据类型可以理解为访问变量的空间时的访问方式。
int 4 内存里数据结合的方式。
float 4
2、数据类型
int char float double void *
指针类型
4
*p p是指针类型的变量 ,p就占用内存空间,4 就有自己的地址。
有自己的空间。p的空间里放指针类型的值。

指针就是地址 错误的

数据类型 找到数据类型最重要

举例`验证:代码参见point.c

int p;
int *p;
int **p;
int arr[3];

数组是类型?
arr是数组的名字。数组的名字就是数组的首地址。
有3个元素,每个元素的类型都是int类型的。
一共占用了12个字节的内存空间。这12个字节的内存空间是连续的。

int *p[3];
指针数组还是数组指针
p是数组的名字 这个数组里有三个元素,每个元素都是指针类型的

int main(int argc,char *argv[]){
}

int arr[3];
char *p=arr;
p+1

int arr[2][3];
同一个地址,使用不同的访问方式会得到不同的结果。
int arr[2][3]={{1,2,3},{4,5,6}};
arr 是数组的名字,有2个元素。arr[0] arr[1]。元素的类型是
int [3]类型

arr[0] 是数组的名字,有3个元素,每个元素是整型的。

arr+1 int[3]
arr[0]+1 int

int (*p)[3];
p是指针类型的变量。要找出数据类型?
int [3]
p+1; 1代表多少个字节?
12
数组指针

void *malloc(size_t size);
返回值是地址的函数。void的意思是对内存的空间不访问。

void (*p)(void)
p是指针类型的变量 数据类型 void (void)
函数的名字就是函数的入口地址。
int (*func_t)(int,int); padd psub pmul pdiv
func_t 指针类型的变量.
int (int,int) 数据类型。

int (*p[4])(int,int);

*p[4] p是数组的名字 这个数组里有4个元素,每个元素都是指针类型的。

struct node{
    int num;
    struct node *next;
};
int p;
int *p
int **p;
int *p[3];
int(*p)[3];
void *malloc();
int (*p)(int,int);
int (*p[4])(int,int);

3、运算符的优先级及其结合性。
4、变量的作用域和生命周期

三、使用typedef定义类型
使用typedef为类型定义别名

为了程序的可读性,需要为类型定义别名。

uint16_t unsigned short
uint32_t unsigned long
pid_t  pthread_t sigset_t key_t

typedef struct node{
    int num;
    struct node *next;
}node_t;

三个步骤:
1、定义类型的变量或者常量 int count_t
2、在第一步的前边加上typedef 变量的名字就是原来类型的别名。 typedef int count_t; count_t 就是int的别名
3、使用别名定义变量 count_t c;

举例

1、char *str_t;
str_t  是变量  *
typedef char *str_t;
str_t  st1,st2;=====char *st1,*st2;

2、

typedef struct node{
    int num;
    struct lnode *next;    
}node_t;
node_t  类型   
typedef node_t *node_p;
node_p  node_t *

node_p h;
node_p *q;
3、int arr_t[3];
typedef int arr_t[3];
arr_t
int[3];
arr_t a;
arr_t b[2];   b是数组的名字   数组里有两个元素,每个元素都是arr_t类型的。是一维数组类型的别名
举例验证  代码参见 arr.c
4、int (*f_t)(int,int);
typedef int (*f_t)(int,int);
f_t f;

int (*p_t)[3];
typedef int (*p_t)[3];
p_t a;

补充 :
大端和小端
大端就是高位字节放在内存的低地址中。
小端是高位字节放在内存的高地址中。

作业:编写代码实现判断主机字节序。

int arr[3]={321,322,323};
char *p=arr;
*p *(p+1);    *(p+12);

代码参见 point_a.c
回调函数
只要是有类型的变量,就可以作为函数的参数。
指针类型的变量也可以作为函数的参数。
int(*f)(int,int);
把函数作为另一个函数的参数传递进去,这样的函数称为回调函数

举例说明 回调函数 参见pmath文件夹。

数据类型

四、GDB调试器的使用

gcc bash makefile gdb
使用gdb调试程序。步骤
1、在编译链接生成可执行文件的时候,加-g/-ggdb参数。
生成的可执行程序带有调试信息。
gcc main.c pmath/*.c -g
2、使用gdb调试可执行程序
gdb a.out
调试器命令
l list 列出程序的源代码
b 函数名/行号 在函数或行号处设置断点
r run 运行程序,到断点处停下。
n next 执行一条语句。
p 变量或常量的名字 输出变量的值
s step 下一步 切换到函数中执行
q quit 退出

总结:
一、动态库的使用
二、c指针
三、typedef定义别名
四、gdb调试器的使用

Responses