zoukankan      html  css  js  c++  java
  • (转)Linux下C++开发初探

    1.开发工具

        Windows下,开发工具多以集成开发环境IDE的形式展现给最终用户。例如,VS2008集成了编辑器,宏汇编ml,C /C++编译器cl,资源编译器rc,调试器,文档生成工具, nmake。它们以集成方式提供给最终用户,对于初学者而言十分方便。但是,这种商业模式,直接导致用户可定制性差,不利于自动化,集成第三方工具的能力弱。例如,无法定制一些宏来处理一些重复操作;体会不到自动化makefile一步到位快感;无法远程登录到服务器上进行开发;无法使用某种”粘合剂”来把第三方工具(例如,文本工具,字符串工具)有效地调用起来。可以说,良好的商业支持和傻瓜式开发,是它们主要的优点。
        在linux下,开发工具被切割成一个个独立的小工具。各自处理不同的问题。例如,编辑器(emacs, vim)用来进行编辑程序的,调试器(gdb)用来调试程序,编译器(GCC)用来编译和链接程序的,性能分析工具(gcov, gprof)用来优化程序的,文档生成器(doxygen)用来生成文档的。同时,还有一些系统工具和系统知识,我们是很有必要了解的:程序自动化机制 makefile,系统粘合剂shell,系统查找工具grep, locate, find。其它的工具(例如ctags, OCI公司的MPC等等),一旦熟练掌握,它们将成为你手中的利器。

       主要是一些针对LINUX下开发工具使用的经验之谈。由于,工具品种繁多,我们没有能力也没有必要一一介绍。对于LINUX下IDE工具,例如 eclipse, anjuta等,它们虽然也很实用,但是使用起来比较简单,而且目前还算不上主流。所以,它们将不被着重介绍。同时,本文也不打算写成各个工具的操作手册,只着眼于介绍各个工具的想要解决的问题、运行机理和主要特性。

    1.1编辑器

        要进行开发,第一件事情就是选择一个合适的编辑器。编辑器选择有几个要素:
        1)减少不必要的编辑动作,减少编辑的时间。
        一切能够无二义性描述出来的编辑任务,都可以而且应该能被自动化。例如,每一个C++程序都会有一个main函数;我们在定义.h文件时,都希望加入一些预处理指令#define来帮我们解决重复引用同一个头文件而带来的麻烦。鼠标操作总是比键盘操作要慢的。这方面EMACS做得可算是到了极致。所以, EMACS用户经常会吹嘘:他们编辑的速度等同于他们思考的速度。
        2)可扩展性高。
        程序员预期的编辑器应该能提供一些编程的帮助,例如,语法高亮,自动补齐,自动排版,语法检查等等。留心观察一下gedit, vim, emacs, ultraEdit,就会发现它们提供的远不是windows 记事本,写字板提供的那么简陋的功能。对于一种新的语言,新的语法,它们应该能很方便地提供支持,而不停留在一种或几种固定的语言上。
        3)用户可定制性高。
        如果想长期从事研发, 特别是linux/unix下研发的话,那么你很有必要学好一个功能足够的编辑器。有这么一句话:Linux下程序员分为三种,使用emacs的,使用vi的,还有其它。EMACS是Stallman用lisp语言写的一个GPL的编辑器。我们这里所说的emacs指的是GNU emacs,而非Xemacs。由于它的开放性,我们可以把它打造成一个功能强大的IDE。我们在安装好CGYwin之后,也可以在Windows系统下使用 EMACS。CGYwin和MINGW是第三方写的一个在Windows系统上模拟POSIX系统的工具。
        EMACS与其说的是一个编辑器,倒不如说它是一个操作系统。我们可以用它来写编程,写wiki,收发邮件等等。EMACS主要是通过两种方式来进行扩展:el脚本(elisp是lisp的一种方言)和第三方扩展包。EMACS的入门成本很高。由于是纯键盘操作,所以需要记忆大量的快捷键;功能强大是通过用户添加一些扩展包,lisp脚本来实现的。如何正确配置和修改是很需要耐心和技巧的。

    1.2编译器

        编译器首选GCC(GNU COMPILER COLLECTION)。原因有两个,它是GNU开源的,同时它对标准C++的支持度高达96.15%。而VC++6.0的支持度只有83.43%。 GCC不仅是通常意义上的C或C++的编译器,它还可以编译java等其它语言。gcc是gnu c的编译器,g++是gnu c++的编译器, 而EGCS(Enhanced GNU Compiler Suite)可以认为是gcc的改进版。
        编译语言从源程序到目标代码会经过如下几个阶段:源程序->汇编程序->编译成obj程序->链接成最终可执行程序。我们可以通过一条编译指令来完成所有步骤。也可以分步执行。gcc有三个重要选项-E(只进行预处理), -S(生成汇编代码), -g(生成带原代码调试符号的可执行文件,如果想用gdb调试的话,就应该在编译时打开这个选项)。
        GCC可以看作一个软件包,除了编译工具,它还集成了调试器gdb,性能分析工具gcov, gprof。只要我们装好了GCC,这些强大工具就可以直接使用了。
        通过gcov,我们可以查看一个程序,源代码中每行代码的运行次数。我们优化运行次数最多的代码,那么就可以大大优化程序。使用gcov时,需要打开 GCC的fprofile-arcs和ftest-coverage两个选项。gcov中常用的选项有-b分支统计信息。
        通过gprof工具,我们可以查看函数之间的调用顺序,及各个函数运行的时间。我们可以将gprof理解为linux/unix自带工具time的加强版。使用gprof时,需要打开GCC的pg选项。
        gcov和 gprof的共同点是在编译程序时,加入自己的一些辅助信息,由此来进行程序诊断。除了,这些优化手段,我们还可以使用一些内存泄漏工具,来减少野指针,未释放的内存空间。 
    调试器
        GDB即GNU的调试器,它是GCC附带的一个性能优质的调试器。通过GDB和脚本结合,我们可以很好的实现回归测试。
        GDB可以运行于CLI和GUI两种模式。默认GDB是CLI模式的,我们可以去下载和安装GUI模式的GDB,例如xxgdb, ddd等。一个更好的方式是在 EMACS中使用GDB。GDB包括visual studio工具的所有调试功能,还包括它没有的功能。它除了支持,我们一般的设置断点,单步跟踪,step in, step out, step over等,还有一些强大的功能。在gdb中,我们可以有以下几种暂停方式:断点(BreakPoint)、观察点(WatchPoint)、捕捉点(CatchPoint)、信号(Signals)、线程停止(Thread Stops)。
    下面列举几个让我印象深刻的功能。1)通过 watch指令,可以让程序在某个变量的值发生变化时,暂停下来。2)通过print指令,在程序运行时,设置变量的值,运行一个程序自身支持的一个方法。3)通过until指令,我们可以让程序在运行到某个程序时暂停下来。4)通过break.. if指令,使得程序在满足某个bool表达式时,暂停下来。

    1.3粘合剂

        我想通过“粘合剂”这个词来表达将多个工具粘合起来的“胶水”。例如,通过shell脚本,我们可以把OS命令,sed指令,awk指令,其它脚本文件等串联起来,发挥它们的合力。在linux C++编程中,我们不可避免地会使用makefile文件。通过,它我们可以把编译指令,生成文档操作,清除操作等等串联起来。从某种意义上来看,它也相当于一个粘合剂。
    makefile的出发点是,维护好一个项目中众多文件的依赖关系,由此得到一个源程序的拓扑图。当我们只修改图中某个结点时,重新编译时就只需要将拓扑图中关联的链路进行编译就好了。由此,大大缩短了编译的时间。make有两大概念:dependencies和rules。规则rule即针对每一个依赖关系 dependency定义一个操作规则。这个细粒度的分离,就可以使我们可以定制软件构建的行为。例如,修改使用的编译器,修改includepath, 修改libpath, 修改编译选项等等。我们常见的VC中的nmake,功能和make是类似的。
        make使用的重点和难点是编写Makefile文件。Makefile的语法相对其它语言来说是很不一样的,我们要特别注意TAB键和空格键的区别。有很多工具可以用来帮助我们生成Makefile。最出名的就是GNU的autoconf了。一个GNU程序的编写,需要autoscan, aclocal, autoconf, automake这四个工具。
    我们知道GNU软件安装的三步曲是:./configure, make, make install。其中./configure就是根据autoconf, alocal等工具生成一个makefile文件。make指令就是调用make指令来根据makefile文件的规则来编译源程序。而make install就是执行makefile中的install规则指出的操作(一般是copy操作)。而make clean就是执行makefile中的clean规则指出的操作(一般是rm操作)。我们用Eclispe+CDT开发Managed C++ Project时,它就是通过objects.mk,subdir.mk,sources.mk三个文件来生成Makefile。我们注意观察编译时的输出信息,就可以看到显示的Makefile文件的内容。
    可以说,如果想编译出跨平台的C++程序,那么makefile是一种最方便的机制。OCI公司为Douglas C.Schmidt的ACE,TAO开源社区编写了一段伟大的perl脚本--MPC。它由平台信息,一个规则文件,源代码,生成用户想要的工程文件,例如Make, Nmake, Visual C++ 6, Visual C++ 7等等。Google Web Tookit, Celtix做的事情与之类似,不过它们是针对JAVA的,而MPC是针对C++的。

    2. 基本开发流程

    2.1 代码的编写

    对于移植工程来讲,基本代码都在Windows下完成,只需要吧代码传到Linux下,然后在Linux下面组织源码目录即可。对于传到Linux编辑,可以使用Linux下的vi工具来完成,也可以通过UltraEdit以Ftp方式打开Linux下的文件进行编辑。vi是Linux下面最常用的一个文本编辑器,后面将会介绍vi的一些基本用法。

    有一点值得注意,Windows下文本里面的回车符包含两个字符‘ ’和‘ ’,而Linux下的文本里面的回车符只包含一个字符‘ ’。这样,如果上传文件的时候没有选择正确的方式,应该使用文本方式上传的使用了二进制方式,或者应该使用二进制方式上传的使用了文本方式,那么在Linux下都会出现问题,打开的文本当中每一行的行尾就会出现一个‘^M’字符。可以通过vi的匹配替换功能(稍后会做介绍)或者重新按照正确的方式上传来解决。

    2.1.1 vi简介

    vi是Linux下最常用的一个文本编辑器,小巧而且功能强大,一次我们把它单独拿出来做一下介绍。如果想了解更详细的信息,请执行man vi查看其联机帮助文档。

    2.1.2 命令模式和编辑模式

    vi的工作模式包括命令模式和编辑模式两种。命令模式下可以执行vi中定义的一些命令,这些命令跟一些特定的键相对应,命令模式下所有的键盘相应将会作为命令来解释。编辑模式就是编辑文档的模式,在编辑模式下所有键盘的相应都为作为文档输入的内容。通过ESC键可以从编辑模式切换到命令模式。通过一些编辑命名可以从命令模式进入编辑模式。

    2.1.3 基本命令

    基本命令指的是在命令模式下,通过敲键执行的命令,这里我们介绍几个常用的命令:

    i             在当前开始插入,进入编辑模式

    I             在行首开始插入,进入编辑模式

    a             在当前字符后追加,进入编辑模式

    A            在行尾追加,进入编辑模式

    x            删除当前光标处的字符

    X            删除当前光标前面的字符

    D            删除从光标位置到行尾的所有字符

    dd           删除当前行

    dw          删除当前的单词

    u            取消刚才的操作

    G            跳到文件末尾

    此外,在命令模式下,通过输入‘/’可以进行查询,通过输入‘:’可以输入一些其他命令。输入‘:’可以输入的命令包括:

    q            退出

    w           保存

    wq          保存退出

    q!         强制退出,不保存

    w!        对受保护的文件强制写,包括只读文件

    set number     显示行号  (set nu  也可以)

    数字       跳到某一行

    2.1.4 查找和匹配

    vi的查找功能也非常强大,命令模式下通过输入‘/’就可以进入查找模式,可以输入要查找的关键字。然后可以通过‘n’来查找下一处。

    在输入‘:’后,还可以输入一些匹配替换的命令——“%s”。命令的格式为“:%s /str1/str2,执行之后将把当前文件中所有str1替换成str2。举一个典型的例子,前面我们说过,Windows下的文本文件如果以二进制的方式传到了Linux下,那么vi打开的时候每行的行尾就会出现一个“^M”,我们可以用vi打开这个文件,然后通过vi的匹配替换功能去掉这些“^M”。命令格式如下:

           :%s /^M//

    其中“^M”通过CTRL+V 和 CTRL+M来输入。  

    2.2 编译

    2.2.1  简单编译

           对于简单的程序,如只有几个源文件,可以直接使用编译器进行编译,或者把几条编译命令写在一个脚本文件里面,通过执行脚本文件实现工程的编译和连接。比如只有一个hello.cpp文件的工程,可以通过如下命令编译:

    CC –o hello hello.cpp

    其中CC是编译器,不同的系统下面可能有不同的编译器。一般来说,大多数Linux系统下的C编译器都叫cc,而C++编译器叫CC。Linux下面带的C编译器为gcc,C++编译器为g++。-o参数用来指定输出的目标的名称,也就是编译后执行程序的名称。这种情况下编译和连接一步完成。

    对于稍微负责一些的程序,包含多个源文件的,可以编写一个编译脚本,相当于windows下的批处理。如下:

    工程中包含hello.cpp、func.cpp、other.cpp,我们可以用如下脚本来实现工程的编译。

            CC –c hello.cpp

            CC –c func.cpp

            CC –c other.cpp

            CC –o hello hello.o func.o other.o

    多个文件情况下,把编译和连接分开执行,先逐个编译源文件,然后再进行链接,形成最终的可执行程序。参数-c就是声明只进行编译操作。

    2.2.2  使用Makefile

    当工程达到一定的规模的时候,2.2.1中的做法显然是不能满足要求的,如果非要那样做,将会带来很大的工作量,而且还非常容易出错。这是我们就要使用Makefile来帮助我们完成工程的编译工作。

    Makefile文件相当于一个工程文件,文件中描述了工程中的源代码、额外需要的库文件及其路径、额外需要的头文件路径已经编译器类型、编译参数等。通过make命令来调入Makefile进行工程的编译。当执行make命令是,会在当前目录下搜索名称为“Makefile”或者“makefile”的文件,作为当前编译的工程文件,也可一指定其他的工程文件,如make –f MyMakefile。

  • 相关阅读:
    LeetCode 382. Linked List Random Node
    LeetCode 398. Random Pick Index
    LeetCode 1002. Find Common Characters
    LeetCode 498. Diagonal Traverse
    LeetCode 825. Friends Of Appropriate Ages
    LeetCode 824. Goat Latin
    LeetCode 896. Monotonic Array
    LeetCode 987. Vertical Order Traversal of a Binary Tree
    LeetCode 689. Maximum Sum of 3 Non-Overlapping Subarrays
    LeetCode 636. Exclusive Time of Functions
  • 原文地址:https://www.cnblogs.com/dangeal/p/4797450.html
Copyright © 2011-2022 走看看