1Unix编程培训讲义陆云海1999.04.19初稿1999.11.26第二版2000.03.23第三版1.开发环境以较为流行的Unix操作系统为例,介绍Unix下开发编程的主要内容。SUN工作站与服务器的操作系统是Solaris,常见版本是Solaris2.5、2.5.1、2.6,较新的是Solaris7(相当于2.7版吧),最新的是Solaris8。Solaris的前身是SunOS,Solaris2.5相当于SunOS5.5。SunOS是基于BSDUnix的,而Solaris是基于UnixSVR4的。HP工作站与服务器的操作系统是HP-UX,常见的是HP-UX10.10、10.20,较新的是HP-UX11.0。DEC服务器(现在该称为Compaq的AlphaServer)的操作系统是DigitalUnix,常见的DigitalUnix4.0D(也叫OSF1),Compaq收购DEC后将DigitalUnix更名为TruUnix64。2.编译系统C/C++由于历史的原因,Unix系统的开发主要是使用C/C++语言。C语言的编译器是cc,这是每个系统都会自带的,在/usr/ccs目录下。对于有些需要使用标准C语言的场合,需要安装ANSIC。C++语言是对C语言的扩充,每家Unix系统的支持就不一样了。SUN机上的C++是SUNVisualWorkshop的一部分,需要安装workshop后才能使用C++,也可以只安装C++。安装workshop需要license。SUN上的C++编译器是CC,一般安装在/opt/SUNWspro/bin目录。HP机上的C++是HP开发工具包SoftBench的一部分。SoftBench的安装需要license。HP机上的C++编译器是CC,一般安装在/opt/CC/bin目录。DEC机上的C++是操作系统内置的,编译器是cxx,在/usr/bin目录。2.1编译过程主要分为编译和链接两大步。具体过程:①编译预处理→②编译→③优化→④汇编→⑤链接。①编译预处理宏定义替换、条件编译、头文件包含、特殊符号(__FILE__、__LINE__等)。②编译常数、关键字、标识符、操作符。词法分析、语法分析。③优化中间代码优化、目标代码的生成。④汇编可重定位文件.o、共享的目标文件.so(.sl)、可执行文件。⑤链接静态链接、动态链接。2.2cc命令以SVR4上的C编译系统为基础,介绍cc的用法。22.2.1cc基本用法cc[选项]源文件[.o文件][库文件]如果源文件中含有main函数,则生成执行文件,缺省情况为在当前目录产生a.out。否则,则只生成.o文件。2.2.2常用选项-o目标文件名:生成指定的目标文件名,可以是执行文件或.o文件,要看有没有-c选项;-c:只生成.o文件;-P:只进行预处理;-C:保留注释;-S:只生成汇编代码;-D符号[=值]:定义符号,若未指明值,则缺省值为1,可以有多个;-Iinclude目录:定义include文件的目录,可以有多个;-L库目录:定义库文件的目录,可以有多个;-l库名:链接时包含库'lib库名.a'或'lib库名.so';-g:加入调试信息;-O[n]:进行代码优化,有的系统还带有优化级别。2.3链接处理链接有静态链接和动态链接两种。2.3.1缺省设置标准的C函数库libc.a(静态库)、libc.so(动态库)主要包含了以下函数:标准I/O函数(stdio.h):标准输入输出、文件输入输出等;字符串处理函数(string.h):strlen、strcpy等;字符分类(ctype.h):isalpha、isupper等;字符串/整数转换(stdlib.h):atoi、itoa等;库函数形式实现的系统调用(unistd.h,sys/types.h,sys/stat.h,fcntl.h):open、read等。2.3.2标准库-l选项指定库名,缺省情况下系统自动包含选项-lc,即自动包含标准C库。如果统一库目录下有库的两个版本,则优先使用动态库。缺省的路径:/usr/ccs/lib、/usr/lib动态库:所有内容被映射到进程虚地址空间中。执行文件小,内存占用小。但是运行时必需存在连接的库。静态库:执行文件只包含所需要的代码。执行文件大,内存占用大。但是运行时不需要连接的库。-dn选项(SUN),指明只进行静态连接。-l选项放在最后较好。32.3.3静态库、动态库的建立静态库,又程档案库,建立步骤:1)生成目标文件cc-c2)用ar命令入档arr$HOME/lib/libtest.amyfunc.o以后就可以使用test库了cc-L$HOME/lib-o.....-ltest静态库的缺点:a.执行文件大,有函数代码的单独拷贝b.运行时每个进程都装入某些相同函数的代码,内存占用大c.函数定义更新后,要重新连接动态库的生成(SUN)cc-KPIC-G-o$HOME/lib/libtest.somyfunc.c(HP)cc-b-o$HOME/lib/libtest.slmyfunc.c2.3.4连接程序搜索目录-L选项指定(SUN)-Bstatic|dynamic指明进行静态或动态连接。环境变量LD_LIBRARY_PATH可以包括两部分,用分号隔开。搜索顺序:LD_LIBRARY_PATH中;的前半部↓-L指定的目录↓LD_LIBRARY_PATH中;的后半部↓标准位置2.3.5动态连接程序搜索目录连接阶段搜索方法同2.3.4。运行阶段使用环境变量LD_RUN_PATH指明自定义的动态库的位置。标准位置只有/usr/lib。运行阶段的搜索也可以使用LD_LIBRARY_PATH环境变量,而且效果更好,因为即使动态库被移到另一个目录,也可以被找到。尽量不要使用硬编码(连接时指定库文件名的全路径名),因为这样的话,当动态库所在目录被移动后,运行不会成功。对于静态库无此问题(想想看,为什么?)。2.4预定义的符号__sun__unix__sparc__i3864__SVR4__hp9000s700__hp9000s800__hppa__hpux__PA_RISC1_1_HPUX_SOURCE__PPC(PowerPC)3.调试3.1简介SUN机和DEC机上的符号调试器是dbx,图形界面的是debugger。HP机上的符号调试器xdb。一般的Unix系统都支持汇编级的调试器adb。命令组:流程控制:断点、单步、连续变量检查:显示、修改变量的值函数调用栈的显示汇编语言级的调试源程序的显示编译和连接时加上-g选项。运行时应去掉此选项,尤其是在HP机上,否则占用太多的空间。使用strip命令也可以去除执行文件中的调试信息。哪些情况下需要调试:coredumpdbxa.outcore边运行、边调试dbxa.out活动进程执行很慢时dbx进程名进程号软中断3.2dbx的常用命令执行和跟踪stop设置断点clear清除断点run启动运行rerun重新运行runargs设置运行参数5cont继续运行next执行下一条语句,不进入函数内部step单步执行,可以进入函数内部显示和名字display显示变量的值(一直显示)down到函数调用堆栈的下一级up到函数调用堆栈的上一级where当前在函数调用堆栈的哪一级,程序中断处的源文件名和行数print显示变量的值(只显示一次)访问源文件cd改变目录pwd当前目录edit编辑文件file改变当前源文件files列出所有的源文件的名称func列出当前函数名funcs列出所有的函数名line改变当前行list显示几行源程序search在文件中搜索字符串use设置目标搜索路径运行时检查check-access|-leaks|-memuse|-alluncheckshowleaksshowmemusesuppressunsuppress杂项commands列出dbx的命令和简要解释help求助命令,后可跟希望得到解释的命令dalias显示别名dbxbugreport创建dbx的bug报告模板dbxenv显示或修改dbx的环境debug显示或改变要被调试的程序history显示历史命令kill-l显示所有已知的信号的标识、名字和描述kill杀掉控制的进程quit退出dbxsetenv设置环境变量sh调用sh执行命令source执行指定的文件中的命令!执行历史命令!!执行上条命令debugger6toolenv{cwd|font|width|srclines|cmdlines...}3.3xdb的常用命令命令行:xdb[-ddir][-Pprocess_ID][objectfile[corefile]]-d指定源程序所在目录-P指定正在运行的进程的IDobjectfile执行文件corefilecore文件窗口模式命令ts切换分屏模式(源程序窗口、汇编窗口)w[size]设置源程序窗口的行数(最多为主窗口行数减3)u刷新屏幕U清除并重画屏幕路径映射命令D目录名定义源程序所在目录,目录名要用引号括起来文件查看命令v显示下一屏程序v行号显示指定行号的程序,放在窗口中央L显示文件名、进程名、行号、当前行程序+[行数]向前移动指定行数(缺省为1行)-[行数]向后移动指定行数(缺省为1行)/[字符串]向前搜索字符串(缺省为上次搜索的字符串)?[字符串]向后搜索字符串(缺省为上次搜索的字符串)n重复上一次的/或?命令N与n命令类似,但是方向相反显示格式[count]formchar[size]count数目formchar格式符(对于数字,小写表示整数,大写表示长数据)size单元大小格式符n一般格式(normal)(d|D)十进制数(decimal)(u|U)无符号十进制数(o|O)八进制数(octal)(x|X)十六进制数(hexadecimal)(z|Z)二进制数(binary)(b|B)以十进制显示一个字节c显示一个字符C显示一个宽字符(e|E)以指数浮点格式显示(f|F)以一般浮点格式显示7(g|G)以g型浮点格式显示a显示以表达式作为首地址的字符串r显示一个对象的模板R显示一个对象的模板,基类也被显示s显示以表达式作为首字节的指针的地址的字符串t显示表达式(通常是变量名或过程名)的类型T与t相同,但对于C++的类和结构对象,也显示基类和结构类型信息p显示包含表达式指定的地址的过程名S结构或类对象的格式化输出k与S相同K与S相同,除了对于C++也显示基类信息size的等价符号b1字节(char)s2字节(short)l4字节(long)D8字节(double)L16字节(longdouble)数据显示和修改命令pexpr相当于pexpr\npexpr\format以format格式显示expr的内容pexpr?format以format格式显示expr的地址p-[[\]format]显示后一单元的数据p+[[\]format]显示前一单元的数据pclass::显示类的静态成员的值l[proc[:depth]]l[[[class]::][proc[:depth]]]列出当前过程(函数)的所有参数和局部变量la列出所有断言lb列出所有断点ld列出所有目录lsl列出所有共享库lz列出所有信号lf[string]列出所有的或匹配的源文件名lg[string]列出所有的或匹配的全局变量ll[string][@library]列出所有的或匹配的标号lm[string]列出所有的或匹配的宏lp[[class]::][string]列出所有的或匹配的函数名ls[string]列出所有的或匹配的特殊变量lx列出异常stop-on-throwand-catch状态(C++).lcl[string]列出所有的或匹配的类(C++).lct[string]列出所有的或匹配的类模板(C++).8ltf[string]列出所有的或匹配的模板函数(C++).lft[string]列出所有的或匹配的函数模板(C++).lo[[class]::][st