Day22、大型项目开发的文件组织、动态链接、动态库、静态链接、静态库gdb调试工具

编写一个函数,实现字符串的拷贝,不允许利用库函数   strcpy()

使用strcpy的原型   man strcpy

char *tstycpy ( char *dest , const char*src)

功能:完成字符串的拷贝,将src指定内存中的内容拷贝到dest指定的内存中

参数:dest目标地址   src源地址

1) 为什么返回值是char*?

因为需要知道目标地址?可以通过dest知道目标地址

strlen(strcpy(dest,”tang”));

strcpy(dest1,strcpy(dest,”qiao”));

char * 是为了函数的嵌套调用 (留一手)

2) 为什么dest前边没有const,而src前面需要const?

因为src指定的地址的内存中的内容不能修改,而dest指定的地址的内容可以更改。

 

  1#include<stdio.h>

  2char *tstrcpy(char *dest,const char *src);

  3int main(void){

 4     charname[20]="tang";

 5     char name1[20],name2[20];

 6    tstrcpy(name2,tstrcpy(name1,name));

 7    printf("name1=%s\nname2=%s\n",name1,name2);

 8     return 0;

  9 }

 10char *tstrcpy(char *dest,const char *src){

 11    int i=0;

 12    while(src[i]!='\0'){

 13        dest[i]=src[i];

 14         i++;

 15     }

 16    dest[i]='\0';

 17    return dest;

 18 }

方法二:

  1#include<stdio.h>

  2char *tstrcpy(char *dest,const char *src);

  3int main(void){

 4     charname[20]="tang";

 5     char name1[20];

 6     tstrcpy(name1,name);

 7    printf("name1=%s\n",name1);

 8     return 0;

  9 }

 10char *tstrcpy(char *dest,const char *src){

 11    char *p_str=dest;

 12    while((*(dest++)=*(src++))!='\0'){

 13     }

 14    *dest='\0';

 15    return p_str;

 16 }

 

学好C语言的三要素

(1)      常量和变量的区别

(2)      变量的访问方式  : 先通过变量的名字找到变量的地址,然后根据类型读取变量的内容(什么是数据类型?数据类型的本质就是数据的访问方式,一次访问几个字节)

 

(3)      运算符的优先级及其结合性

今天内容:

一、            大型项目开发的文件组织

软件工程:

第一:熟悉客户的业务

第二:提取客户的需求,需求描述书

第三:需求分析

第四:系统设计

第五:编码

第六:测试

第七:交付

第八:后期技术支持

 

接口要规定好

头文件:头文件内容:

1) 头文件卫士

2) 函数的声明

3) 类型的定义(结构体typedef)

typedef的使用

typedef int Count ;

Count i ; i 是什么类型?  int

typedef int(*fun_t)(int,int);

fun_t f ; f是什么类型?

 

typedef三步走:

第一步:int Count: 先定义类型的变量,区分出谁是变量,谁是类型

第二步:typedefint Count ; 加上typedef,原来的变量就变为类型的别名。

第三步:Count i ; 用别名定义一个变量。 i是 int 类型

 

Char *str ; str 是变量    *是类型    str里面放地址,存字符类型的地址 char是指针访问一个字节

int a=3;

str=&a;会有警告

typedef char *str; 

str p1,p2;  p1 p2是指针型变量

int ( *math_t ) ( int , int ); 定义了函数指针

int *math_t ( int ,int ); 定义返回值为指针的函数  

int *p;定义一个指针变量,一次访问4(int)个字节

int *p[3];定义一个数组,数组里的每一个成员都是指针类型,

int ( *p )[3] ; 数组指针  p是一个指针类型的变量,除了(*p)都是访问方式,3个int为一个基本访问单位,一次访问3*int =12个字节

int **p ;

 

typedef int ( *math_t ) ( int , int );

math_t 指针类型;本质就是 int ( * ) ( int ,int )

int ( *p ) ( int , int );定义了一个变量,变量名是p,指针类型的,访问方式int ( int , int )

math_t p; 相当于 int ( *p ) ( int , int );

二维数组本质是一维数组,只是分成几个单位,每个单位是一个小的一位数组

计算机内存存放字节地址分两种:小端和大端  

低字节放到高地址 ( 大端) 和低字节放到低地址(小端)。   PC用小端,网络用大端。

4) 宏定义

5) 变量的声明

变量的定义和变量的声明:

变量的定义是为变量分配空间的,变量的声明不需要分配空间

若在一个文件里已经定义过int var_i ; 变量的定义

在另一个文件里只需声明extern int var_i  变量的声明

 

第一步:写头文件tmath.h

第二步:实现文件tmath.c

第三步:写含有main函数的测试代码

第四步:对每个.c源文件进行单独的编译,编译成.o文件

第五步:对多个.o文件进行链接,形成可执行文件

 

nm 二进制文件的名字

-T  函数的实现在本文件中

-U  在本文件中使用了这个函数,但是这个函数的代码在本文件中不存在

tarena@tarena-virtual-machine:~/day22$ nmtmath.o

00000000 T add

0000002a T div

0000001e T mul

0000000d T sub

tarena@tarena-virtual-machine:~/day22$ nmtest.o

        U add

        U div

00000000 T main

        U mul

        U printf

        U sub

tarena@tarena-virtual-machine:~/day22$ gcctmath.o test.o

tarena@tarena-virtual-machine:~/day22$ nm  ./a.out

080483f4 T add

0804841e T div

08048430 T main

08048412 T mul

        U printf@@GLIBC_2.0

08048401 T sub

tarena@tarena-virtual-machine:~/day22$ gcc-v test.o tmath.o

gcc –v test.o tmath.o :-v参数就是将程序从 .o文件到可执行文件的这个编译过程全部显示在屏幕上)

tarena@tarena-virtual-machine:~/day22$nm/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o

00000000 R _IO_stdin_used

00000000 D __data_start

        U __libc_csu_fini

        U __libc_csu_init

        U __libc_start_main

00000000 R _fp_hw

00000000 T _start

00000000 W data_start

        U main

(main也是被系统调用,一起链接)

链接的原理:此时发生在编译阶段的链接是静态链接,T和U结合

(以上说的编译阶段是指大的编译阶段,即.c文件到a.out之间的阶段)

跟运行时库文件进行链接,形成可执行文件

tarena@tarena-virtual-machine:~/day22$ nma.out

080483f4 T main

08048506 T mul

        U printf@@GLIBC_2.0

080484f5 T sub

此时printf 还没有使用

动态链接:将代码加载到内存以后进行链接,又成为延迟绑定。

PS:程序在运行时才把动态库的printf函数加载进来,即执行a.out时,进行链接。

静态库:函数库,库中存放的是.o文件,这些文件发生在静态链接阶段。

动态库:库文件中存放的也是.o文件,但是和这些函数的链接发生在加载到内存以后。

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

静态链接发生在编译阶段,是将代码的实现拷贝到函数的调用位置,所以静态链接的文件比较大。可执行文件不依赖于库文件

动态链接发生在加载到内存以后,文件比较小。但是可执行文件必须依赖于库文件。

ldd 可执行文件    作用:查看可执行文件依赖于哪些动态库文件。

tarena@tarena-virtual-machine:~/day22$ ldda.out

       linux-gate.so.1=>  (0xb7781000)

       libc.so.6=> /lib/i386-linux-gnu/libc.so.6 (0xb75c3000)

       /lib/ld-linux.so.2(0xb7782000)

二、gdb调试工具

第一步:在编译的时候,加-g或-ggdb参数

gcc test.c tmath.c –g

第二步:gdb 可执行文件名

gdb a.out

gdb命令:

l  list

b main  在main函数处设置断电

b  函数的名字或者是数字(行号)

断点  函数执行到断点就停下来

r 是run 继续运行

n 是下一步

p  变量名 printf这个变量的内容

s step 一步一步的意思,单步执行

q  退出调试工具

 

作业:用gdb命令跟踪:

1、void swap(int x,int y)

2、void swap(int *x,int *y)

3、数组作为函数的形参

 

 

 

 

三、静态库的制作和使用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值