头文件与库文件

来源:互联网 发布:贵州省2017旅游数据 编辑:程序博客网 时间:2024/05/02 00:53

 

1、为什么只要包括<iostream.h>就能使用cout这样的东西,而iostream.h里面,只有一些声明

      那是因为默认情况下,链接器会把标准库链接到你的程序中。而那个库文件(扩展名为.lib,.dll,.a,.so ),其中包括了具体实现的代码编译后的结果(二进制的机器码)。而<iostream.h>这个头文件就是打开库的钥匙。

扩充:

库文件
    1、概论
      先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。
      在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。静态链接把应用程序所需的全部内容都是从库中复制了出来,所以静态库本身并不需要与可执行文件一起发行。但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库

       静态库的原则是“以空间换时间”,增加程序体积,减少运行时间;
       动态库则是“以时间换空间”,增加了运行时间,但减少了程序本身的体积。

      对动态链接库,我们还需建立如下概念:
    (1)DLL 的编制与具体的编程语言及编译器无关
      只要遵循约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以相互调用。譬如Windows提供的系统DLL(其中包括了Windows的API),在任何开发环境中都能被调用,不在乎其是Visual Basic、Visual C++还是Delphi。
      (2)动态链接库随处可见
      我们在Windows目录下的system32文件夹中会看到kernel32.dll、user32.dll和gdi32.dll,windows的大多数API都包含在这些DLL中。kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函数主要控制用户界面;gdi32.dll中的函数则负责图形方面的操作。
      一般的程序员都用过类似MessageBox的函数,其实它就包含在user32.dll这个动态链接库中。由此可见DLL对我们来说其实并不陌生。
      (3)VC动态链接库的分类
      Visual C++支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。
      非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。

      2、静态链接库
      对静态链接库的讲解不是本文的重点,但是在具体讲解DLL之前,通过一个静态链接库的例子可以快速地帮助我们建立“库”的概念。
      在VC++6.0中new一个名称为libTest的static library工程,并新建lib.h和lib.cpp两个文件,lib.h和lib.cpp的源代码如下:
//文件:lib.h
      #ifndef LIB_H
      #define LIB_H
      extern "C" int add(int x,int y); //声明为C编译、连接方式的外部函数
      #endif

 //文件:lib.cpp
      #include "lib.h"
      int add(int x,int y)
      {
            return x + y;
      }

       编译这个工程就得到了一个.lib文件,这个文件就是一个函数库,它提供了add的功能。将头文件和.lib文件提交给用户后,用户就可以直接使用其中的add函数了。
      标准Turbo C2.0中的C库函数(我们用来的scanf、printf、memcpy、strcpy等)就来自这种静态库。
      下面来看看怎么使用这个库,在libTest工程所在的工作区内new一个libCall工程。libCall工程仅包含一个main.cpp文件,它演示了静态链接库的调用方法,其源代码如下
      #include <stdio.h>
      #include "../lib.h"
      #pragma comment( lib, "..//debug//libTest.lib" ) //指定与静态库一起连接
      int main(int argc, char* argv[])
      {
            printf( "2 + 3 = %d", add( 2, 3 ) );
      }
      静态链接库的调用就是这么简单,或许我们每天都在用,可是我们没有明白这个概念。代码中#pragma comment( lib , "..//debug//libTest.lib" )的意思是指本文件生成的.obj文件应与libTest.lib一起连接。如果不用#pragma comment指定,则可以直接在VC++中设置,依次选择tools->options->directories->library files菜单或选项,填入库文件路径。
      这个静态链接库的例子至少让我们明白了库函数是怎么回事,它们是哪来的。我们现在有下列模糊认识了:(1)库不是个怪物,编写库的程序和编写一般的程序区别不大,只是库不能单独执行;
(2)库提供一些可以给别的程序调用的东东,别的程序要调用它必须以某种方式指明它要调用之。
      以上从静态链接库分析而得到的对库的懵懂概念可以直接引申到动态链接库中,动态链接库与静态链接库在编写和调用上的不同体现在库的外部接口定义及调用方式略有差异

2、#include到底做了什么?

      仅仅把<>或""中的内容插入到文件处。和你打开头文件然后ctrl-c,ctrl-v的效果是一样的。 

3、<>与""意义一样吗?

      <>与""差不多。
<>先在系统目录(就是设置的include目录)中查找。
而""则是先在工程所在的目录中寻找。

4、头文件顶部的#ifndef是干什么的?

      通过#ifndef与#define来防止同一个文件被反复包含。

5、多次include同一个文件会不会有什么问题

      要看情况。对于函数原型,没有什么问题。对于函数的实现,类的定义等实际实现则不行。就是“只定义一次”原则,声明可以有多次。

6、如何发布自己写的库?

     把声明与实现写在同一个.hpp文件中(如Boost的大部分)。
把声明与实现放在不同的文件中,提供.mak文件给用户自己编译,然后设置include和lib目录(这个普遍用于类库的发布)。

原创粉丝点击