《UnixLinux下CC开发技术概览》由会员分享,可在线阅读,更多相关《UnixLinux下CC开发技术概览(17页珍藏版)》请在金锄头文库上搜索。
1、 内部公开内部公开本文中的所有信息均为中兴通讯股份有限公司内部信息,不得向外传播Unix/Linux 下 C/C+开发技术概览 1. 平台差异简介 Windows 和 Unix 是当前两大主流操作系统平台,基于 C/C+的开发人员经常会面临这 两个平台之间的移植的问题。Unix 作为一个开发式的系统,其下有出现了很多个分支,包 括 Sun 的 Solaris、IBM 的 AIX、HP Unix、SCO Unix、Free BSD、苹果的 MAC OS 以及开源的 Linux 等。对于这些 Unix 的分支操作系统,其实现又有很大的差别,因此开 发人员又要针对这些不同的系统进行移植。本文的目的就
2、是介绍一下 Windows 平台和 Unix 平台之间的差别,并简单介绍一下不同 Unix 分支操作系统之间的差别,在移植开发 过程中的一些注意事项,同时简要介绍一下 Unix 下开发的一般流程和常用的开发调试工 具。 关于平台之间的差异,主要是 Windows 平台和 Unix 平台之间的差异,这里着重介绍一 下这两个平台在 C/C+开发中存在的差异,其间会穿插介绍一些 Unix 不同分支之间的差 异。 1.1 语言特性的差异语言特性的差异,指的是不同操作系统平台中,实现 C+/C 时的一些细微的差异, 忽略这些差异可能会带来一些特别隐蔽的错误。而且可能是致命的错误。所以,了解语言 特性的差
3、异,对于在 Unix 移植来说非常重要。如果考虑系统多多个平台支持,就必须了 解在不同平台下语言特性的差异,从开发一开始就把这些因素考虑进去,这样才能最低限 度的降低移植的过程中工作量。 1.1.1 字节顺序的差异字节顺序指的主要是整型变量在内存中的存储方式。在计算机中,数据都是以二进 制方式存储的,包括在内存和硬盘中。而计算机又以 8 位二进制作为一个存储单元。在 32 位系统中,一个整型的存储需要四个存储单元。也就是说要把一个 32 位的整数分割成 位四段分别进行存储,而每一段的存储位置就是字节顺序的差异。为了清楚的表示每段存 储的先后位置,我们用 16 进制来表示一段的值,下表列出了在
4、Unix 系统和 Windows 系 统中整数 20000 在内存中的情况。 十六进制表示0x00004E20 Windows 内存表示20 4E 00 00 Unix 内存表示00 00 4E 20 如表中所示,Windows 中存储方式和该整数的 16 进制表示是相反,是一种低位在前高位 在后的存储顺序。而 Unix 下的存储顺序和正常的 16 进制表示的顺序相同,称为高位在前 低位在后的顺序。这种差异带来的问题,主要体现在以下几个方面: 网络通信时 当 Windows 和 Unix 之间发生网络数据传输,传输一个整型数据(如一个数据包的长度) 的时候,如果不经处理直接把内存中的数据传输过
5、去,那么在对方看来完全是另一个数据, 这样就会造成问题。如 Windows 下面发送过去一个 20000(0x00004E20) ,在 Unix 下面收到的数据就会被理解成 541982720(0x204E0000) ,这简直是天壤之别。 文件存储和读取时 跟网络传输类似,如果在 Windows 下面把某个整数写到了文件中,然后在 Unix 下面打 开这个文件读取该数据,就会出现跟上面类似的问题。这个问题主要体现在不同平台之间互操作时,在多平台开发过程中,尤其时在网络内部公开内部公开本文中的所有信息均为中兴通讯股份有限公司内部信息,不得向外传播应用开发的时候,两个平台之间数据交互是非常普遍的,
6、所以这个问题也就显的很普遍。 解决这个问题的方法就是交互的双方采用一种相同的数据编码标准,就是数据在传输和存 储的时候采用什么方法进行编码,具体的做法有一下几种: 1 数字转换成字符传进行交互 2 协商一个同意的字节顺序,根据自己平台的字节顺序还原数据 3 采用其他标准的编码方式,如 ASN1 编码跟这个问题类似,32 位系统和 64 位系统的差异也会出现这样的问题,解决方法跟这个问 题的解决方法相同。在 32 位系统和 64 位系统中,长整型(long)分别用 32 位和 64 位 表示,这样,在不同系统之间交互的时候必然会出现整型数据表示方式不同的问题。目前 大多数 Windows 系统都
7、是 32 位的系统,而 Unix 中很多都是 64 位的,尤其是大型的服 务器,所以这个问题必须引起重视。 1.1.2 变量的作用域差异 在不同的系统下,由于编译器的不同,对变量作用域的实现机制也有所不同,这里以 Windows 下的 VC 和 Solaris 下的 CC 这两个编译器为例做一个简单的比较说明。 在 C+的开发过程中,我们经常会有这样的用法:for(int i=0;i .depends #执行的命令-include .depends #%.o:%.cpp # echo Compling file: $? please wait . # $CXX $CXXFLAGS -c $?
8、$BIN_NAME:$OBJSecho Linking file: $ please wait .$CXX -o $ $OBJS clean:rm -f $BIN_NAME $OBJS *pure .depends在 Makefile 文件中,大体来说分为“宏定义” 、 “文件列表”和“依赖关系”三个部分。 宏定义中定义 Makefile 中可以使用的一些宏,定义好一个宏以后,在 Makefile 的后面部 分可以通过宏引用来获得宏的值。像编译器、编译参数等通常都会定义成宏,然后通过修 改宏的值就可以修改编译器类型及编译参数。在更复杂的 Makefile 中,宏定义中还会包 含依赖的库文件、需
9、要增加的库文件路径及头文件路径、程序中预定义的宏等。 其实文件列表也是一个宏,只是考虑到他的重要性,所以单独作为一个部分来介绍。在后 面的依赖关系中,就会用到这个宏。文件列表中定义了工程包含的所有源文件和这些源文 件编译以后生成的目标文件。目标文件可以通过源文件列表生成。上面我们使用 $SRCS:.cpp=.o来生成目标文件列表,意思就是说把源文件中所有扩展名为“.cpp” 换成“.o” 。 依赖关系部分是 Makefile 文件的关键,其中定义了多个依赖关系。每一个依赖关系又包 括一个依赖规则和一组执行的命令。依赖规则由目标和依赖对象构成,也就是说这个目标 依赖于指定的依赖对象。当执行 ma
10、ke 的时候,如果发现目标不存在或者目标的依赖对象 的更新时间比目标还新,就会执行依赖关系中的命令,来完成对目标的编译。Makefile 中 可以定义多个目标,每个目标对应一个依赖关系和一组命令。执行 make 的时候,可以执 行要编译的目标。如 make clean 表示检查执行目标 clean。all 是一个默认的目标,即执 行 make 不加参数的时候,就会默认为要检查执行 all 这个目标。Makefile 中可以为 all 目标指定依赖对象和要执行的命令。Makefile 中,也可以只指定依赖关系,不指定要执行 的命令,这种情况大多用于依赖对象也是一个定义的目标。Make 在检查依赖
11、关系的时候, 如果发现依赖对象也是一个目标,就会先去检查这个目标的依赖关系,看是否需要重新编 译这个目标,然后才会执行本依赖关系下面的命令。 为了实现源文件的编译,我们在依赖关系中需要定义源文件和目标文件之间的依赖关系, 然后执行程序和这些目标文件之间建立一个依赖关系。这样就可以实现整个工程的编译了。 上面的这个 Makefile 中,包含了两种定义这种依赖关系的方法,一种是通过编译器的“-M”命令来形成依赖关系文件,然后把这个文件的内容 include 到当前的依赖关系中,另 一种是通过匹配替换的做法,直接通过源文件和目标文件的映射关系形成依赖关系。红色内部公开内部公开本文中的所有信息均为中
12、兴通讯股份有限公司内部信息,不得向外传播字体部分和蓝色字体部分分别代表这两种做法。 “-M”参数是 gcc/g+编译器特有的,其 他编译器一般没有这个参数,应该使用第二种做法。 在不同的系统中,Makefile 的语法会有一些细微的差别,在进行多平台移植的时候应该注 意这个问题,分别对不同的系统编写不同的 Makefile。 2.2.3 automake 和 autoconf Makefile 基本结构虽然很简单,但是妥善运用这些规则就可以变换出许多不同的花样。 却也因为这样,许多刚刚开始学习写 Makefile 时会觉得没有规范可以遵循,每个人写出 来的 Makefile 都不大一样,不知道
13、从哪里下手,而且常常会受到自己的开发环境的限制, 只要环境参数不同或者路径更改,可能 Makefile 就得跟着修改修改。虽然有 GNU Makefile Conventions (GNU Makefile 惯例例)订出一些使用 GNU 程式设计时撰写 Makefile 的一些标准和规范,但是内容很长而且很复杂,并且经常作一些调整,为了减 轻程序开发人员维护 Makefile 的负担,因此出现了 Automake。 程序设计者只需要写一些预先定义好的宏 (macro),提交给 Automake 处理后会产生一 个可以供 Autoconf 使用的 Makefile.in 文件。再配合利用 Aut
14、oconf 产生的自动培植 设置文件 configure 即可产生一份符合符合 GNU Makefile 惯例的 Makeifle 了。automake 的基本用法,是先用 autoscan 搜索当前目录,然后形成一个 configure.scan 文件,然后以 configure.scan 文件为蓝本,形成一个 configure.in 文 件,这是最终需要的文件。然后使用 aclocal 处理一下本地的宏,再使用 autoconf 生成 一个 configure 脚本文件。configure 脚本文件用来形成最终的 makefile。之后编译一 个 Makefile.am,定义 autom
15、ake 需要的一些宏,包括源文件列表等。执行 automake,形成 Makefile.in 文件。这样,需要的准备工作基本完成。编译的时候,通 过执行 configure 脚本,会自动生成 Makefile 文件,然后再执行 make 就可以了。关于 automake 的详细用法请查看参考资料。 2.3 运行和调试 跟 Windows 不统,Unix 下面的文件只有有可执行的权限就可以执行,不像 Windows 那 样依赖于扩展名。所以 Unix 下的执行程序大都没有扩展名,任何文件只要给了一个执行 权限,就可以直接运行。可以通过 chmod +x 来给一个文件增加可执行的权限。编译后 形成
16、的目标文件,通常都已经有了执行的权限,所以可以直接执行。 2.3.1 设置运行环境 对于简单的程序来说,不用设置什么运行环境,直接运行即可。对于负责的程序来讲,可 能执行程序和需要的共享库文件不在同一个目录下,就需要设置一些运行环境了。设置运 行环境主要就是设置共享库的路径。Unix 下的共享库,相当于 Windows 下面的动态库 (dll 文件),是一种以.so 为扩展名的文件。系统的共享库存放在/usr/lib 下面,程序运行 的时候会自动去那个目录下面寻找需要的共享库。对于用户自己开发的共享库,一般不能 放在/usr/lib 目录下面,而是放在用户的程序目录下面。一个 比较复杂的程序,其目录结 构分的比较清晰,并不是把所有的文件都放在一个目录下面。下面列出了一个典型的目录 结构: mainpath 程序主目录 mainpath/bin 执行程序目录 mainpath/lib