13.C语言高级编程(未完)

1.GNU工具

编译工具:把一个源程序编译为一个可执行程序

调试工具:能对执行程序进行源码或汇编级调试

软件工程工具:用于协助多人开发或大型软件项目的管理,如make、CVS、Subvision

其他工具:用于把多个目标文件链接成可执行文件的链接器,或者用作格式转换的工具。

2.GCC简介

全称为GNU CC ,GNU项目中符合ANSI C标准的编译系统 

编译如C、C++、Object C、Java、Fortran、Pascal、Modula-3和Ada等多种语言

GCC是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%~30%

一个交叉平台编译器 ,适合在嵌入式领域的开发编译

gcc所支持后缀名解释 
.c		C原始程序
.C/.cc/.cxx	C++原始程序
.m		Objective-C原始程序
.i		已经过预处理的C原始程序
.ii		已经过预处理的C++原始程序
.s/.S	汇编语言原始程序
.h		预处理文件(头文件)
.o		目标文件
.a/.so	编译后的库文件

1.编译器的主要组件

分析器:分析器将源语言程序代码转换为汇编语言。因为要从一种格式转换为另一种格式(C到汇编),所以分析器需要知道目标机器的汇编语言。

汇编器:汇编器将汇编语言代码转换为CPU可以执行字节码

链接器:链接器将汇编器生成的单独的目标文件组合成可执行的应用程序。链接器需要知道这种目标格式以便工作。

标准C库:核心的C函数都有一个主要的C库来提供。如果在应用程序中用到了C库中的函数,这个库就会通过链接器和源代码连接来生成最终的可执行程序。

2.GCC的基本用法和选项

Gcc最基本的用法是∶gcc [options] [filenames] 
-c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。 

-o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。

-g,产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。 

-O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。

-O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。

-I  dirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。

-L  dirname,将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过程中使用的参数。

3.GCC编译过程

GCC的编译流程分为四个步骤:

        预处理(Pre-Processing)

        编译(Compiling)

        汇编(Assembling)

        链接(Linking)

3.调试器--Gdb调试流程

首先使用gcc对test.c进行编译,注意一定要加上选项‘-g’

# gcc -g test.c -o test 
# gdb test 
GNU gdb Red Hat Linux (6.3.0.0-1.21rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb)

1.Gdb的使用切记点 

4.C语言高级编程

1.条件编译

#define  _DEBUG_   1
#if  _DEBUG_
printf(“The macro _DEBUG_ is defined\n”);
#else
printf(“The macro _DEBUG_ is not defined\n”);
#endif

2.结构体

在实际的处理对象中,有许多信息是由多个不同类型的数据组合在一起进行描述,而且这些不同类型的数据是互相联系组成了一个有机的整体。此时,就要用到一种新的构造类型数据——结构体(structure),简称结构。

结构体的使用为处理复杂的数据结构(如动态数据结构等)提供了有效的手段,而且,它们为函数间传递不同类型的数据提供了方便。

概念

        结构体是用户自定义的新数据类型,在结构体中可以包含若干个不同数据类型和不同意义的数据项(当然也可以相同),从而使这些数据项组合起来反映某一个信息。

在大括号中的内容也称为“成员列表”或“域表”

其中,每个成员名的命名规则与变量名相同

数据类型可以是基本变量类型和数组类型,或者是一个结构体类型用分号“;”作为结束符。整个结构的定义也用分号作为结束符

定义一个职工worker结构体如下:
struct worker
{   
	 long number;
    char name[20];
    char sex;		
    int age;          //  age是成员名
    float salary;
    char address[80];
};      			//注意分号不能省略
 int  age = 10;    //age是变量名 

定义几个职工变量
struct worker{
    long number;
    char name[20];
    char sex;
    int age;
    float salary;
    char address[80];
    char phone[20];
};
struct worker worker1,worker2;

#define WORKER struct worker;
WORKER
{  long number;
   char name[20];
   char sex;
   int age;
   float salary;
   char address[80];
   char phone[20];  };
   WORKER worker1,worker2;

在定义类型的同时定义变量 这种形式的定义的一般形式为:         

                struct 结构体名       

                        {          

                                成员列表;         

                        }变量名;

Example:
struct worker
{   long number;
    char name[20];
    char sex;
    int age;
    float salary;
    char address[80];
    char phone[20];
} worker1,worker2;

直接定义结构类型变量 其一般形式为:          

                struct      //没有结构体名   

                         {        

                                成员列表;       

                        }变量名;

struct
{
    long number;
    char name[20];
    char sex;
    int age;
    float salary;
    char address[80];
    char phone[20];
} worker1,worker2; 

1.结构体变量的使用形式

结构体变量是不同数据类型的若干数据的集合体。在程序中使用结构体变量时,一般情况下不能把它作为一个整体参加数据处理,而参加各种运算和操作的是结构体变量的各个成员项数据

结构体变量的成员用以下一般形式表示:              结构体变量名.成员名

worker1.number;worker1.name;worker1.sex;
worker1.age;worker1.salary;worker1.address;
worker1.phone  

在定义了结构体变量后,就可以用不同的赋值方法对结构体变量的每个成员赋值。

strcpy(worker1.name,”Zhang San”);
worker1.age=26;
strcpy(worker1.phone,”1234567”);
worker1.sex=’m’;

除此之外,还可以引用结构体变量成员的地址以及成员中的元素。例如:引用结构体变量成员的首地址&worker1.name引用结构体变量成员的第二个字符worker1.name[1]引用结构体变量的首地址&worker1

struct student wan={”Wan Jun”,’m’,20,” SuZhou Road No.100”};
strcpy(wan.name,” Wan Jun”);
wan.sex = ’m’;
wan.age = 20;
strcpy(wan.addr, ” SuZhou Road No.100”); 

3.结构体数组

结构体数组的定义

        具有相同结构体类型的结构体变量也可以组成数组,称它们为结构体数组。结构体数组的每一个数组元素都是结构体类型的数据,它们都分别包括各个成员(分量)项。 定义结构体数组的方法和定义结构体变量的方法相仿,只需说明其为数组即可。可以采用三种方法:  

        

struct student
{
  char name[20];
  char sex;
  int age;
  char addr[20];
};
struct student stu[3]; 

struct student
{
  char name[20];
  char sex;
  int age;
  char addr[20];
}stu[3]; 

struct 
{
  char name[20];
  char sex;
  int age;
  char addr[20];
}stu[3]; 

结构体指针

4.共用体及typedef

1.共用体

共用体的概念         

        在C语言中,不同数据类型的数据可以使用共同的存储区域,这种数据构造类型称为共用体,简称共用,又称联合体。共用体在定义、说明和使用形式上与结构体相似。两者本质上的不同仅在于使用内存的方式上。         

        定义一个共用体类型的一般形式为:

                union 共用体名         

                        {             

                                成员表列;             

                                        };

在程序中经常使用结构体与共用体相互嵌套的形式。 即共用体类型的成员可以是结构体类型,或者结构体类型的成员是共用体类型

下列结构体类型datas的第三个成员是共用体类型: 
struct datas
{
   char *ps;
   int type;
   union
   {
     float fdata;
     int idata;
     char cdata;
    }udata;
};

2.typedef

5.内存管理

C/C++定义了4个内存区间:

        代码区/全局变量与静态变量区/局部变量区即栈区/动态存储区,即堆区。

静态存储分配

        通常定义变量,编译器在编译时都可以根据该变量的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间

        在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

动态存储分配

        有些操作对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。

所有动态存储分配都在堆区中进行

从堆上分配,亦称动态内存分配。程序在运行的时候用malloc申请任意多少的内存,程序员自己负责在何时用free释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

堆内存的分配与释放

当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。

堆区是不会自动在分配时做初始化的(包括清零),所以必须用初始化式(initializer)来显式初始化

动态内存

malloc/free
     void * malloc(size_t num)
     void   free(void *p)

malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数

malloc申请到的是一块连续的内存,有时可能会比所申请的空间大。其有时会申请不到内存,返回NULL。

malloc返回值的类型是void *,所以在调用malloc时要显式地进行类型转换,将void * 转换成所需要的指针类型

如果free的参数是NULL的话,没有任何效果。

释放一块内存中的一部分是不被允许的

注意事项:

        删除一个指针p(free(p);),实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身,释放堆空间后,p成了空悬指针

        动态分配失败。返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。

         malloc与free是配对使用的, free只能释放堆空间。如果malloc返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存malloc返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。

        动态分配的变量或对象的生命期。无名对象的生命期并不依赖于建立它的作用域,比如在函数中建立的动态对象在函数返回后仍可使用。我们也称堆空间为自由空间(free store)就是这个原因。但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放是一件很容易失控的事,往往会出错。 

野指针

        不是NULL指针,是指向“垃圾”内存的指针。“野指针”是很危险的。 

        “野指针”的成因主要有两种:

                指针变量没有被初始化。

                指针p被free之后,没有置为NULL,让人误以为p是个合法的指针

                指针操作超越了变量的作用范围。这种情况让人防不胜防

6.Makefile

工程管理器,顾名思义,是指管理较多的文件 Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件的内容来执行大量的编译工作

Make将只编译改动的代码文件,而不用完全编译。

Makefile基本结构

Makefile是Make读入的唯一配置文件

        由make工具创建的目标体(target),通常是目标文件或可执行文件

        要创建的目标体所依赖的文件(dependency_file)

        创建每个目标体时需要运行的命令(command)

        注意:命令行前面必须是一个”TAB键”,否则编译错误为:*** missing separator.  Stop.

Makefile格式
    target  :   dependency_files
    <TAB>  command
例子
hello.o :  hello.c hello.h
	gcc  –c  hello.c  –o  hello.o
sunq:kang.o yul.o
	gcc kang.o yul.o -o sunq
kang.o : kang.c kang.h 
	gcc –Wall –O -g –c kang.c -o kang.o
yul.o : yul.c 
	gcc - Wall –O -g –c yul.c -o yul.o

-Wall:表示允许发出gcc所有有用的报警信息.      -c:只是编译不链接,生成目标文件”.o”      -o file:表示把输出文件输出到file里关于更多的用man工具

创建和使用变量

创建变量的目的:

用来代替一个文本字符串:

               1.系列文件的名字  

                2. 传递给编译器的参数  

                3. 需要运行的程序  

                4. 需要查找源代码的目录

                5. 你需要输出信息的目录    

                6. 你想做的其它事情。

OBJS = kang.o yul.o
CC = gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
	$(CC) $(OBJS) -o sunq
kang.o : kang.c kang.h
	$(CC) $(CFLAGS) -c kang.c -o kang.o
yul.o : yul.c yul.h
	$(CC) $(CFLAGS) -c yul.c -o yul.o
递归展开方式VAR=var
例子:
foo = $(bar) 
bar = $(ugh) 
ugh = Huh? 
$(foo)的值为?
echo $(foo)来进行查看

优点:  

         它可以向后引用变量  

缺点:

                不能对该变量进行任何扩展,例如 CFLAGS = $(CFLAGS) -O 会造成死循环

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ARM小白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值