统计

  • 随笔 - 50
  • 文章 - 42
  • 评论 - 147
  • 引用 - 0

留言簿(6)

随笔分类

文章分类

Link

搜索

  •  

积分与排名

  • 积分 - 162640
  • 排名 - 161

最新评论

阅读排行榜

评论排行榜

在 console mode 中使用 C/C++ 编译器
  • CL.exe
    1. cl /c [filename]   /c为只编译不链接的意思,默认cl.exe工具会在编译之后自动调用LINK.EXE进行链接
    2. cl.exe运行需要指定include、lib等环境变量
    3. [filename]需要指定文件全名(包含后缀名)
    4. C/C++的编译是针对文件进行的
  • lib.exe Microsoft库管理工具
    用于打包编译后的库文件(obj),使生成一个库文件(lib)

    obj文件和lib文件一样,可以直接用于link.exe链接工具中,生成exe可执行文件。lib.exe的作用只是打包,将多个obj打包为一个
  • link.exe 链接工具
    link [file(s)]  /dll选项用来生成一个动态链接库(dll)
  • 库文件的编写:
    库文件中只包含需要的函数及数据即可,不需要main函数,也不能有main函数
    库文件的调用者,需要用extern关键字申明要调用的外部函数
  • 目前以lib后缀的库有两种,一种为静态链接库(Static   Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import   Libary,以下简称“导入库”)。  
        静态库是一个或者多个obj文件的打包,所以有人干脆把从obj文件生成lib的过程称为Archive,即合并到一起。比如你链接一个静态库,如果其中有错,它会准确的找到是哪个obj有错,即静态lib只是壳子。 
        动态库一般会有对应的导入库,方便程序静态载入动态链接库,否则你可能就需要自己LoadLibary调入DLL文件,然后再手工GetProcAddress获得对应函数了。有了导入库,你只需要链接导入库后按照头文件函数接口的声明调用函数就可以了。
        导入库和静态库的区别很大,他们实质是不一样的东西。静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。
  • 动态链接库(dll)
    一般为提高程序可读性,使用#define DllExport __declspec(dllexport)宏定义Dll中需要导出的函数;在每个需要导出的函数前使用DllExport,例如DllExport int multiple(int x,int y)
    生成一个Dll的方法:1.使用cl.exe /c [filename]将源文件生成库文件 2.使用link.exe /dll [filename.obj]将此obj文件生成dll
    调用Dll的方法一:1. 使用extern指定外部函数名 2.在程序中直接使用将要调用的Dll的函数名 3.链接时加入上一步骤中生成的库文件(.lib)
  • 方法二:运行时动态加载
    C代码示例:
    //lib.c
    #define DllExport __declspec(dllexport)
    DllExport int multiple(int x,int y)
    {
     return x*y;
    }
    //libCaller.c
    #include "windows.h"
    //extern  int multiple(int x,int y);
    typedef UINT (CALLBACK* LPFNDLLFUNC1)(int,int);
    HINSTANCE hf;
    LPFNDLLFUNC1 func;
    main()
    {
         
    hf= LoadLibrary("lib.dll");
         if(hf!=0)
         {
              func = (LPFNDLLFUNC1)GetProcAddress(hf,"multiple");
              printf("Multiple:%d\r\n",func(5,12));
              FreeLibrary(hf);
        }
    }
  • Windows中的.lib文件分两种类型
    1.静态库文件,用于编译时供其他对象引用 2.动态链接库的导出文件。链接时使用,无需使用LoadLibrary动态加载。
  • Link.exe工具在使用.def文件生成DLL时的两种命令行语句:
    1. 如果DEF文件中没有LIBRARY语句,需要同时指定/DEF /DLL选项
    2. 如果DEF文件中有LIBRARY语句,只需指定/DEF选项即可生成DLL
  • Microsoft Visult Studio开发工具中CL.exe工具CL的意思及Compile和Link
  • 生成DLL的方式(listed in recommended order of use):
    1. 在源文件中使用VC++自定义关键字__declspec(dllexport)
    2. 使用包含EXPORTS语句的.def文件
    3. 使用Link.exe工具的/EXPORT选项(定义导出函数)
  • //DEF源文件Sample
    EXPORTS
    add
  • //DLL源文件Sample
    int add(int x,int y)
    {
     return x + y;
    }
  • int substract(int x,int y)
    {
     return x-y;
    }
  •  

     

     

    我总是鼓励 C/C++ 的学习者,在刚接触这个程式语言的时候,先以 console mode(DOS-like)程式为目标。换言之,不要一开始就想写 GUI 程式、想开视窗、想有眩目亮丽的画面 -- 那只是未走先飞,揠苗助长罢了。
    所谓 console 程式,就是文字模式的程式,我们可以在其中好好把 C/C++ 的语言根基练好,而不会分心於其他暂无必要的 GUI 枝节上。
    我一直以为,这是理所当然的事情,却也一直发现,有不少大专院校的大一 C/C++ 课程,同学们必须写个小作家、小画家、小算盘┅做为期中或期末作业。
    果然世界不能大同,各人看法殊异 :)
    我不但认为 C/C++ 程式开发对象初期要以 console mode 为主,我也认为,C/C++ 的程式开发环境,初期也要以 console mode 为主。换言之,不要一开始就进入整合环境(IDE)。整合环境中那麽多视窗、那麽多功能、那麽多预设值,会让程式新手眼花撩乱,无法掌握程式编译过程中一些有价值的知识与经验。
    等我们对编译程序有了起码的了解,再来使用整合环境,我认为这才最好。
    所以不论在 <深入浅出 MFC> 或 <多型与虚拟> 书籍中,我都会简述console mode 下的作业方式。<深入浅出 MFC> 在 p.224 列出,<多型与虚拟> 在 p.233 列出。
    但仍然偶而会收到网友(不论是否上两本书的读者)的询问,询问console mode 的编译方式,或询问他们所遭遇的问题。
    我再次整理这个题目。再有类似问题,我就可以整篇 mail 给发问者了。
    ★★ 注意:以下适合 PC 环境 ★★
    ●C/C++ 编译器需要的环境变数设定
    古早以来,PC 上的 C 编译器,就需要两个环境变数:
    LIB:这个环境变数告诉编译器说,必要的 libraries 在哪里(哪个磁碟目录下)
    INCLUDE:告诉编译器说,必要的 header files 在哪里(哪个磁碟目录下)
    另外,为了让我们能够在任何 working directory 都叫得到编译器,当然我们必须设定 PATH。
    从古早以来,一直到现在,C/C++ 编译器都需要这三个环境变数。
    ●以 Visual C++ 为例
    以 Visual C++ 为例,如果安装後的档案布局如下:
    C:\MSDEV\VC98\BIN : 这里放有编译器 CL.EXE
    C:\MSDEV\VC98\INCLUDE : 这里放有 C/C++ header files
    C:\MSDEV\VC98\LIB : 这里放有 C/C++ standard libraries
    那麽你可以写一个批次档如下:
    set PATH=C:\MSDEV\VC98\BIN;C:\MSDEV\COMMON\MSDEV98\BIN
    set INCLUDE=C:\MSDEV\VC98\INCLUDE
    set LIB=C:\MSDEV\VC98\LIB

    之所以需要另外设定 PATH=C:\MSDEV\COMMON\MSDEV98\BIN,是因为编译器 CL.EXE 执行时需要 MSPDB60.DLL,而它被安装於 C:\MSDEV\COMMON\MSDEV98\BIN 之中。
    如果你写的程式不只是单纯的 C/C++ 程式,还用到了 MFC,一样可以在 console mode 下编译,这时候你的环境变数应该如此设定:
    set PATH=C:\MSDEV\VC98\BIN;C:\MSDEV\COMMON\MSDEV98\BIN
    set INCLUDE=C:\MSDEV\VC98\INCLUDE;C:\MSDEV\VC98\MFC\INCLUDE
    set LIB=C:\MSDEV\VC98\LIB;C:\MSDEV\VC98\MFC\LIB

    多指定了 MFC\INCLUDE 和 MFC\LIB,就可以让编译器和联结器找到 MFC 的 header files 和 libraries。如果你还需要用到 ATL,就得在 INCLUDE 环境变数中再加上 C:\MSDEV\VC98\ATL\INCLUDE。
    ●以 Borland C++Builder 为例
    以 Borland C++Builder 为例,如果安装後的档案布局如下:
    C:\BORLAND\CBuilder3\BIN : 这里放有编译器 BCC32.EXE
    C:\BORLAND\CBuilder3\INCLUDE : 这里放有 C/C++ header files
    C:\BORLAND\CBuilder3\LIB : 这里放有 C/C++ standard libraries
    那麽你可以写一个批次档如下:
    set PATH=C:\BORLAND\CBuilder3\BIN
    set INCLUDE=C:\BORLAND\CBuilder3\INCLUDE
    set LIB=C:\BORLAND\CBuilder3\LIB

    ●如何在 console 中编译 C/C++ 程式
    首先,开启一个 DOS Box(DOS Prompt, DOS VM),然後在该 DOS box 中执行上述写好的批次档,完成环境变数的设定。你可以再在 DOS 提示号下键入 set 命令,看看环境变数的设定内容正确与否。
    然後就可以直接在 DOS 提示号下键入编译器名称,开始编译了。如果你使用 Visual C++,就这麽做:
    C:\> CL test.cpp
    如果你使用 C++Builder,就这麽做:
    C:\> BCC32 test.cpp
    至於特殊情况下需要什麽特殊的 options,就必须自己查一下啦。只要执行 CL /? 或 BCC32(其後不加任何引数),便可看到所有的 compile options。
    ●编译器与联结器的关系
    早期的编译过程与联结过程是分开的。换句话说我们必须做两个动作:
    C:\> Cl test.cpp
    C:\> LINK test.obj xxx (xxx 代表各个必要的 libraries)

    或是:
    C:\> BCC32 test.cpp
    C:\> TLINK32 test.obj xxx (xxx 代表各个必要的 libraries)

    如今的编译过程与联结过程当然还是分开的,但是我们的动作只需一个:
    C:\> CL test.cpp
    或是:
    C:\> BCC32 test.cpp
    这是因为编译器变聪明了,除非你指定 /c option(表示只编译不联结),否则它便自动为你呼叫联结器进行联结动作。过去以来颇令 programmer烦恼的「该使用哪些 libraries」的问题,编译器也有了聪明的解决方案:它将程式中用到的 library functions 记录起来,同时也录下它们所属的library 名称,於是联结器就可以从这个表格中知道要联结哪些 libraries 了。
    ●环境变数与 DOS VM(Virtual Machine)的关系
    你可以同时开起多个 DOS Box,但是你不能够在某个 DOS Box 中执行上述批次档而在另一个 DOS VM 中享受其环境设定。
    这是因为每个 DOS Box 都是一个 Virtual Machine,彼此谁也看不到谁,互不相干。
    除非你在 autoexec.bat 中就设定好上述那些环境变数。这麽一来,任何一个新开启的 DOS VM 便会因为继承最原始的 DOS VM 环境,而继承了那些变数设定。
    ●环境空间(environment space)不足
    最易造成大家困扰的,就是环境空间(environment space)不足的问题。
    当你安装好 Visual C++,会在其 BIN 子目录中发现一个名为 VCVARS32.BAT 的档案。这个档案其实就是做上述的环境变数设定动作(这在 Visual C++ 安装过程的最後一个步骤有说明。哎,有多少人安装软体不看说明!)。所以,你可以在任何 DOS Box 中执行此档,取代前述我们自己的批次档。
    但是通常大家都有失败的经验,得到 "Out of environment space" 的错误讯息。这是因为 VCVARS32.BAT 使用以下句法:
    set INCLUDE=%MSVCDir%\ATL\INCLUDE;%MSVCDir%\INCLUDE;%MSVCDir%\MFC\INCLUDE;%INCLUDE%
    set LIB=%MSVCDir%\LIB;%MSVCDir%\MFC\LIB;%LIB%

    意思是把 INCLUDE 的原始设定(%INCLUDE%)再附加其他设定,并把LIB 的原始设定(%LIB%)再附加其他设定。如果原始设定已经很长,多来这麽几次,便 "Out of environment space" 啦!
    做法之一是调高环境空间的大小。请在 c:\config.sys 档中加上这行:
    shell=C:\COMMAND.COM C:\ /E:1024 /P
    其中 /E:1024 便是表示将环境空间调为 1024 bytes。(不够?再调)
    做法之二是不要使用 VCVARS32.BAT 的那种「附加」句型,改用前述我们自己的批次档。要知道,我们可能有好几个编译器环境(VC、BCB、G++ ┅),需要轮番测试我们的程式;如果使用「附加」句型,多来几次,再大的环境空间也会消磨殆尽。
    方法一和方法二要双管齐下唷。
    ●有任何规模上的限制吗?
    使用 console 模式(或称 command line 模式)来编译联结程式,程式的大小可否有任何规模上的限制?答案是没有!
    它的缺点是没有工具帮你管理档案、没有预设值让你少打几个字、没有分析工具帮你整理 objects,让你浏览 objects、symbols┅。所以一旦你基本功学会了,要开始中大型程式的设计,当然以整合环境(IDE)为佳。
    ●不要误会
    我这不是开倒车,要大家回到茹毛饮血的时代,都回头去做山顶洞人。而是我觉得,对於一位 C/C++ 初学者,整合环境(IDE)的运用恐怕带来一头雾水,不如先在 console mode 下作业。一方面多认识一些环境设定方面的常识,满好的,一方面比较方便好用,也不必写个 1000 行的小小练习还得启动 五五加农炮,一方面求知的力量可以全部放在语言的练习上头。
    等有了一定的程度,再使用整合环境,就不会如坠五里雾了。

    posted on 2009-03-18 00:00 pear_li 阅读(882) 评论(0)  编辑 收藏 引用 所属分类: C++


    只有注册用户登录后才能发表评论。
    网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理