《01-Linux下的C语言编程基础ppt.ppt》由会员分享,可在线阅读,更多相关《01-Linux下的C语言编程基础ppt.ppt(61页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、LINUX下C语言编程基础RE.ER嵌入式学院2008年3月1内容大纲LINUX下编程标准及基本概念常用的编程工具进程及线程的概念系统调用的基本概念内存布局及库管理C程序运行的基本环境如何调试程序有用的工具如何获取帮助LINUX下编程内容及相互之间的关系2LINUX可爱的小企鹅34相关名词GNU=GNUsNotUnixGPL:GeneralPublicLicense(公共许可协议)LGPL:LibraryGeneralPublicLicense(GNU程序库公共许可协议)5GNUGNU=“GNUsNotUnix”)RichardStallman于1984年发起GNU计划,GNU计划是要实现一个
2、新的操作系统,它类似于Unix的操作系统,但是完全开放。(当时Unix已不是免费软件)刚开始时只包含几个基本的软件:C编译器(gcc)、编译软件make、文本编辑软件Emacs、C语言库(glibc)以及其他一些核心应用程序(ls,cp等)到了1991年,GNU计划依然缺乏一个操作系统”内核”.直到LINUX出现各种使用Linux作为内核的GNU操作系统正被广泛地使用着;虽然这些系统通常被称作为“Linux”,但是它们应该更精确地被称为GNU/Linux系统。6GPLGPL许可证用来保护自由软件在被修改后,依然是自由软件。GPL的特点:GPL软件的提供者可以免费或者付费的向用户提供该软件在用户
3、获取该软件时,必须可以同时得到源代码。得到该软件后,用户可以:执行该软件修改源代码,然后重新发布利用部分未修改的源代码,编写自己的程序,然后发布。动态或者静态链接该GPL软件的二进制形式,编写和发布自己的程序。被发布的程序(上述2,3,4),必须也是GPL软件。7LGPLLGPL许可证用来保护自由软件在被修改后,依然是自由软件。LGPL的特点LGPL软件的提供者可以免费或者付费的向用户提供该软件。在用户获取该软件时,必须可以同时得到源代码得到该软件后,用户可以:执行该软件修改源代码,然后重新发布利用部分未修改的源代码,编写自己的程序,然后发布。动态或者静态连接该GPL软件的二进制形式,编写和发
4、布自己的程序只有在修改源代码的情况下(上述2),被发布的新程序才必须是LGPL软件8LINUX编程标准-ANSI历史历史:ANSI(美国国家标准局)于1989年制定的C语言标准,后来被ISO(国际化标准组织)接受为标准,因此也成为ISOC目标目标:为各种操作系统上的C程序提供可移植性保证,而不仅仅限于类UNIX系统。内容内容:该标准不仅定义了C语言的语法和语义,而且还定义了一个标准库,这个库可以根据头文件划分。9LINUX编程标准-POSIX历史历史:POSIX是PortableOperatingSystemInterfaceforUNIX的首字母缩写词,最初由IEEE开发的标准族,部分已经被
5、ISO接受为国际标准目标目标:保证程序的可移植性。只要保证他们的程序设计的符合POSIX标准,开发人员就能确信他们的程序可以和支持POSIX的操作系统互联。内容内容:这个标准定义了应用程序和操作系统之间的一个接口。10库与系统调用11系统调用系统调用:操作系统提供给外部程序的接口在linux系统中,系统调用函数定义在glibc中系统调用说明系统调用函数通常在成功时返回0值,不成功时返回非零值。如果要检查失败的原因,则要判断全局变量errno的值,errno中包含错误代码许多系统调用的返回数据通常通过引用参数传递。这时,需要在函数参数中传递缓冲区地址,而返回的数据就保存在该缓冲区中不能认为系统调
6、用函数就要比其它函数的执行效率高。要注意,系统调用是一个非常耗时的过程12内容大纲LINUX下编程标准及基本概念常用的编程工具进程及线程的概念系统调用的基本概念内存布局及库管理C程序运行的基本环境如何调试程序有用的工具如何获取帮助LINUX下编程内容及相互之间的关系13LINUX下的常用编程工具编辑工具(vi,emacs)编译工具(gcc/g+)二进制文件工具()项目组织工具(make)版本控制工具(cvs,bugzilla)14二进制文件工具nm:列出目标文件序列”object-file.”中的符号,这样可以帮助程序员定位和分析执行程序和目标文件中的符号信息和它的属性。objdump:显示一
7、个或多个目标文件的信息,由其选项来控制显示哪些特定的信息。通过使用这个工具可以方便的查看执行文件或库文件的信息,如我们可以通过objdump软件反汇编执行程序,看到执行程序的汇编格式。objcopy:将一种格式的文件内容进行转换,并输出为另一种格式的目标文件。15LINUX下编程标准及基本概念常用的编程工具进程的概念进程的概念系统调用的基本概念内存布局及库管理C程序运行的基本环境LINUX文件系统及I/O如何调试程序有用的工具如何获取帮助LINUX下编程内容及相互之间的关系16程序与进程程序:是一个包含可以执行代码的文件,是一个静态的文件进程:是一个开始执行但是还没有结束的程序的实例.就是可执
8、行文件的具体实现.17进程的特征动态性并发性独立性异步性占用资源(结构特性)18进程状态新建状态:进程正在被创建就绪状态:系统正在等待CPU来执行命令执行状态:进程正在运行阻塞状态:进程正在等待某一个事件发生终止状态:进程已经结束了系统正在回收资源19进程状态的转换20常用的进程调度方法时间片优先级先来先服务短作业优先21LINUX中进程的表示方法为了管理进程,操作系统必须对每个进程所做的事情进行清楚地描述,为此,操作系统使用数据结构来代表处理不同的实体,这个数据结构就是通常所说的进程描述符或进程控制块,在linux系统中,这就是task_struct结构,在includelinuxsched
9、.h文件中定义。每个进程都会被分配一个task_struct结构,它包含了这个进程的所有信息,在任何时候操作系统都能跟踪这个结构的信息,这个结构是linux内核中最重要的数据结构22task_struct相关说明,见includelinuxsched.h文件.系统还有一个当前进程指针CURRENT,用来指向正在运行的进程。23task_struct结构分析进程的task_struct结构分为以下几个字段:状态:进程在运行时总是在不停地改变它的状态。在Linux系统中,有以下几个状态:调度信息调度算法需要此信息来决定系统中的那一个进程需要执行。标识符 系统中的每一个进程都有一个进程标识符。进程标
10、识符并不 指向进程向量的索引。每个进程同时还包括用户标识符和工作组标识符。24task_struct结构分析内部进程通讯Linux系统支持信号、管道、信号量等内部进程通讯机制。链接 在Linux系统中,每个进程都和其他的进程有所联系。除了初始化进程,其他的进程都有父进程。一个新的进程一般都是由其他的进程复制而来的。task_struct结构中包括指向父进程,兄弟进程和子进程的指针。时间和计时器内核需要记录进程的创建时间和进程运行所占用的CPU的时间。进程可以使用系统调用设置计时器,并当计时器失效时给进程一个信号。计时器可以是一次性的或周期性的。25task_struct结构分析文件系统进程在运
11、行时可以打开和关闭文件。task_struct结构中包括指向每个打开文件的文件描述符的指针,并且包括两个指向VFS索引节点的指针。VFS的索引节点用来在文件系统内唯一地描述一个文件或目录,并且提供文件系统操作的统一的接口。第一个索引节点是进程的根目录,第二个节点是当前的工作目录。两个VFS索引节点都有一个计数字段用来表明指向节点的进程数。虚拟内存大多数的进程都需要虚拟内存。Linux系统必须了解如何将虚拟内存映射到系统的物理内存。处理器的内容一个进程可以说是系统当前状态的总和。每当一个进程正在运行时,它都要使用处理器的寄存器及堆栈等资源。当一个进程挂起时,所有有关处理器的内容都要保存到进程的t
12、ask_struct中。当进程恢复运行时,所有保存的内容再装入到处理器中。26LINUX中进程的控制启动运行程序前台执行:需要终端后台执行:不需要终端进程结束27程序的执行环境每个程序都接收到一张环境表。与参数表一样,环境表也是一个字符指针数组,其中每个指针包含一个以null结束的字符串的地址。全局变量environ则包含了该指针数组的地址。externchar*environ;我们称environ为环境指针,指针数组为环境表,其中各指针指向的字符串为环境字符串。28程序的执行环境-#includeintputenv(constchar*str);intsetenv(constchar*nam
13、e,constchar*value,intrewrite);两个函数返回:若成功则为0,若出错则为非0voidunsetenv(constchar*name);-实例分析:env.c29重要的环境变量PATH可执行程序的搜索路径LD_LIBRARY_PATH:将其它目录加入到库搜索路径。它的内容应该是由冒号分隔的目录列表设置方法:1、rcS,profile文件2、export命令30C程序的执行与结束C程序总是从main函数开始执行。main函数的原型是:intmain(intargc,char*argv);有五种方式使进程终止:正常终止:从main返回。调用exit。调用_exit。异常终止
14、:调用abort由一个信号终止31exit和_exitexit和_exit函数用于正常终止一个程序exit和_exit函数区别:_exit立即进入内核exit则先执行一些清除处理(包括调用执行各终止处理程序,关闭所有标准I/O流等),然后进入内核。函数原型:#includevoidexit(intstatus);#includevoid_exit(intstatus);3233获取错误信息在调用库函数或者系统调用函数后,绝大多数情况下:执行成功返回0;如果执行失败则返回-1,并对外部局部变量error赋值,以指示具体的错误情况。所有的错误代码都在errno.h中定义。为打印出具体的error值
15、所对应的错误提示信息,一般使用perror函数。34perror()函数的用法函数原型:#includevoidperror(constchar*s);函数说明perror()用来将上一个函数发生错误的原因输出到标准错误(stderr)。参数s所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。使用#includeintmain(void)FILE*fp;fp=fopen(/root/noexitfile,r+);if(NULL=fp)perror(/root/noexitfile);return0;35内存及库管理36C语言的存储空间布
16、局37存储器分配对于动态使用内存空间,我们分堆上来分配ANSIC说明了三个用于存储空间动态分配的函数。malloc。分配指定字节数的存储区。此存储区中的初始值不确定。calloc。为指定长度的对象,分配能容纳其指定个数的存储空间。该空间中的每一位(bit)都初始化为0。realloc。更改以前分配区的长度(增加或减少)。当增加长度时,可能需将以前分配区的内容移到另一个足够大的区域,而新增区域内的初始值则不确定。38存储器分配函数#includevoid*malloc(size_tsize);void*calloc(size_tnobj,size_tsize);void*realloc(void
17、ptr*,size_tnewsize);三个函数返回:若成功则为非空指针,若出错则为NULLvoidfree(voidptr*)39Gcc编译过程一、预处理cpp二、汇编gccS三、编译as四、连接ld40库的概念为什么要使用库?代码重用隐藏具体的函数实现库的类型静态库(.a):将库中相应函数的二进制映像代码直接拷贝到当前编译的程序中。共享库(libxxx.so.x):在编译时只引用库中相应函数的二进制映像代码的入口位置(即不直接拷贝),该程序在运行时从共享库文件中读出该函数代码。为此,需要首先将共享库加载到内存中,从而间接引用。41静态库的使用在自己的程序中引用共享库中的函数#include
18、“libhello.h”intmain()print_hello();return0;编译链接gccousehello_staticusehello.clibhello.a42共享库的使用在自己的程序中引用共享库中的函数#include“libhello.h”intmain()print_hello();return0;编译链接gccWallgcusehello.cousehello.ogccgousehello_dynamicusehello.oL./-lhellolddusehello_dynamicLD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(pwd)43库搜
19、索路径LINUX默认在路径为/lib和/usr/lib下的库文件中搜索在LD_LIBRARY_PATH环境变量所设置的路径下查找在/etc目录下搜索动态装载器的缓存文件/etc/ld.so.cache(此文件由ldconfig创建更新,在RedHad9中,直接由/etc/ld.so.conf文件列出)44LINUX相关资源Linux操作系统中函数库路径如下:/lib/系统必备共享库/usr/lib/标准共享库和静态库/usr/X11R6/lib/X11R6的函数库/usr/local/lib/本地函数库头文件路径/usr/include/系统头文件/usr/local/include/本地头文
20、件共享库及其相关配置文件和管理命令/etc/ld.so.conf/包含共享库的搜索路径ldconfig/共享库管理工具,一般在更新了共享库之后要运行该命令ldd/可查看可执行文件所使用的共享库45静态库的创建编写源代码libhello.clibhello.husehello.c生成库文件目标文件gccclibhello.c使用ar命令创建静态库arrclibhello.alibhello.o其中:r-把目标文件包含在库中,替换任何已经在库中存在的同名目标文件c-创建归档文件。46创建共享库-特殊的编译和连接选项-D_REENTRANT使得预处理器符号_REENTRANT被定义,这个符号激活一些
21、宏特性。-fPIC选项产生位置独立的代码。由于库是在运行的时候被调入,因此这个选项是必需的,因为在编译的时候,装入内存的地址还不知道。如果不使用这个选项,库文件可能不会正确运行。-shared选项告诉编译器产生共享库代码。-Wl,-soname-Wl告诉编译器将后面的参数传递到连接器。而-soname指定了共享库的soname。47创建共享库soname文件:lib+链接库名字+.so+.版本号每当链接库接口改变时都递增版本号。soname文件其实只是一个符号链接而已,指向他的realname文件。realname文件:lib+链接库名字+.so+.版本号.次版本号.发行号发行号是可选的。该文
22、件包含实际代码。linkername文件lib+链接库名字+.so编译器以这个名字来请求指定的链接库。当程序在内部列出所需要的链接库时,仅仅使用soname。当你创建一个链接库时,使用realname。一般性linkername文件在安装链接库的时候创建。linkername文件也只是一个符号链接,指向最新的soname文件或realname文件。建议指向soname文件,因为当你更新库以后,在编译器链接的时候,一般总是想使用新的库。48创建共享库编写源程序Libhello.clibhello.husehello.c生成共享库目标文件。用gcc和fPIC参数将源代码编译成目标代码,这个选项生成
23、的代码与位置无关,可以在任何地址被连接和加载gccgfPICWallgclibhello.c使用-shared选项创建共享库gccgsharedWl,-soname,libhello.so.1.0olibhello.so.1.0libhello.o-lc49创建共享库可以把库文件拷贝到/etc/ld.so.conf中列举出的任何目录中,并以root身份运行ldconfig;运行exportLD_LIBRARY_PATH=pwd,它把当前路径加到库搜索路径中去。50ldd工具ldd工具ldd用来显示执行文件需要哪些共享库,共享库装载管理器在哪里找到了需要的共享库.51dlopendlopen()
24、是一个强大的库函数。该函数将打开一个新库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。比如ApacheWeb服务器利用这个函数在运行过程中加载模块,这为它提供了额外的能力。一个配置文件控制了加载模块的过程。这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了。可以在自己的程序中使用dlopen()。dlopen()在dlfcn.h中定义,并在dl库中实现。它需要两个参数:一个文件名和一个标志。文件名可以是我们学习过的库中的soname。标志指明是否立刻计算库的依赖性。如果设置为RTLD_NOW的话,则立刻计算;如果设置的是RTLD_LAZY,则在需要
25、的时候才计算。另外,可以指定RTLD_GLOBAL,它使得那些在以后才加载的库可以获得其中的符号。当库被装入后,可以把dlopen()返回的句柄作为给dlsym()的第一个参数,以获得符号在库中的地址。使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数52dlopenvoid*dlopen(constchar*filename,intflag)用于打开指定名字的动态链接库,并返回一个句柄flag:RTLD_LAZY,RTLD_NEW,RTLD_GLOBALRTLD_LAZY:在dlopen()返回前,对于动态库中存在的未定义的变量(如外部变extern,也可以是函数)不执行
26、解析,也就是不解析这个变量的地址RTLD_NEW:与RTLD_LAZY不同,在dlopen()返回前,解析处每个未定义的变量的地址,如果解析不出来,dlopen会返回NULL,错位为undefinedsymbol:xxx.RTLD_GLOBAL:是库中被解析出来的变量在随后的其它链接库中也可以使用,即全局有效。53dlsymvoid*dlsym(void*handle,char*symbol)根据动态链接库的句柄与函数名,返回函数名对应的函数的地址。54dlcloseintdlclose(void*handle)关闭动态链接库,handle是调用dlopen函数库的句柄55dlerrercon
27、stchar*dlerror(void)动态库链接库执行失败时,dlerror返回错误信息,若执行成功,则返回NULL56LINUX下编程标准及基本概念常用的编程工具进程及线程的概念系统调用的基本概念内存布局及库管理C程序运行的基本环境如何调试程序有用的工具如何获取帮助LINUX下编程内容及相互之间的关系57如何调试程序GDB工具Binutil系列工具终端输出调试58有用的工具expand:将输出制表符转换为空格,unexpand:将输入空隔转换为制表符,使用-t选项来制定制表符停止位grep:搜索字符串find:查找文件59find命令选项-name按照文件名查找文件。60如何获取帮助Man手册man1命令,可以查看普通用户命令使用介绍man2系统调用,可以查看内核接口系统调用函数man3函数库调用,可以查看普通函数库中的函数man8系统管理命令Info手册GNU的超文本帮助系统How-TO文本文件,包含linux某一方面的信息其他61