EXE;DLL;LIB学习心得

来源:互联网 发布:雷霆主持人音效软件 编辑:程序博客网 时间:2024/06/05 18:32
文件类型的学习心得:

1: .EXE文件

 EXE File英文全名executable file ,译作可执行文件,可移植可执行 (PE) 文件格式的文件,它可以加载到内存中,并由操作系统加载程序执行是可在操作系统存储空间中浮动定位的可执行程序。如记事本程序notepad.exe ,可以用来编辑文档,如:测试.txt双击打开notepad.exe记事本程序来进行编辑处理

目前对可执行文件的理解:

   在源代码中存在main 函数的文件最终链接生成可执行文件:

   在C语言当中,一个程序,无论复杂或简单,总体上都是一个“函数”;这个函数就称为“main() 函数”,也就是“主函数”。比如有个“做菜”程序,那么“ 做菜 ”这个过程就是“主函数”。在主函数中,根据情况,你可能还需要调用“买菜,切菜,炒菜”等子函数。

   main函数在程序中大多数是必须存在的,但是依然有例外情况,比如windows编程中可以编写一个动态链接库(dll)模块,这是其他windows程序可以使用的代码。由于DLL模块不是独立的程序,因此不需要main函数。(相当于孤立的自己编写的函数)

main函数的学习链接:http://c.biancheng.net/cpp/html/725.html ;http://baike.baidu.com/link?url=WbhrCWjlA77wR-MY853QjgQ81mzjb0CQW61vFxiINkRWG5raCOHMNkCEeyVy2enrgEIIxww5JM03Vl6LuQpcCszIp5PncbDsvvn2wPMSKbi#1


2: .DLL文件

       动态链接库(Dynamic Link Library或者 Dynamic-link Library,缩写为 DLL),是微软公司在微软Windows操作系统中,实现共享函数库概念的一种方式。这些库函数的扩展名是 ”.dll"、".ocx"(包含ActiveX控制的库)或者 ".drv"(旧式的系统驱动程序)。

   动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。(相当于exe调用dll)函数的代码位于一个 DLL 文件中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。

   使用动态链接库可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分。例如,您有一个大型网络游戏,如果把整个数百MB甚至数GB的游戏的代码都放在一个应用程序里(直接使用一个包含有函数声明的大的lib),日后的修改工作将会十分费时,而如果把不同功能的代码分别放在数个动态链接库中,您无需重新生成或安装整个程序就可以应用更新。

   动态链接库文件,是一种不可执行的二进制程序文件(相比于有main 函数的exe),它允许程序共享执行特殊任务所必需的代码和其他资源。Windows 提供的DLL文件中包含了允许基于 Windows 的程序在 Windows 环境下操作的许多函数和资源。一般被存放在电脑的"C:\Windows\System32" 目录下。(系统目录  如果exe在他的工作空间(发布时在exe的文件中,调试时在 工程配置文件 所在的目录中)中找不到将会在 系统文件见System32中查找)#####但是经过测试发现 其实并不是 System32文件夹而是 System32 文件下面的System文件夹。

   Windows 中,DLL 多数情况下是带有 ".dll" 扩展名的文件,但也可能是 ".ocx"或其他扩展名;Linux系统中常常是 ".so" 的文件。它们向运行于 Windows操作系统下的程序提供代码、数据或函数。程序可根据 DLL 文件中的指令打开、启用、查询、禁用和关闭驱动程序

3: .LIB 文件:

       目前以lib后缀的库有两种,一种为静态链接库(Static Library,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Library,以下简称“导入库”)。

    静态库是一个或者多个obj文件的打包,所以有人干脆把从obj文件生成lib的过程称为Archive,即合并到一起。比如你链接一个静态库,如果其中有错,它会准确的找到是哪个obj有错,即静态lib只是壳子。(静态链接库其实就是多个函数定义的obj打包,相当于已经完全写好的,并且已经编译好的函数,就等着链接)

   动态库一般会有对应的导入库 lib,方便程序动态载入动态链接库,否则你可能就需要自己LoadLibrary调入DLL文件,然后再手工GetProcAddress(个人的理解 调入文件后得到对应函数的基本地址信息 从而找到函数 )获得对应函数了。有了导入库,你只需要链接导入库后按照头文件函数接口的声明调用函数就可以了

导入库:

   导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。

   导入库和静态库的区别很大,他们实质是不一样的东西。静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。这也是实际上很多开源代码发布的惯用方式:

   1. 预编译的开发包:包含一些.dll文件和一些.lib文件。其中这里的.lib就是导入库,而不要错以为是静态库。但是引入方式和静态库一样,要在链接路径上添加找到这些.lib的路径。而.dll则最好放到最后产生的应用程序exe执行文件相同的目录。这样运行时,就会自动调入动态链接库。

   2. 用户自己编译: 下载的是源代码,按照readme自己编译。生成很可能也是.dll + .lib(导入库)的库文件(理解是原来编译opencv的方法,编译了opencv然后,然后生成了一堆 dll 和 对应的 lib , 之后让自己的代码使用这些 库文件)

   3. 如果你只有dll,并且你知道dll中函数的函数原型,那么你可以直接在自己程序中使用LoadLibary调入DLL文件,然后使用GetProcAddress调用DLL中的函数。(找到dll文件后 还要根据地址找到 对应的 函数

当DLL被链接时,链接程序要查找关于输出变量,函数,或C++类的信息,并自动生成一个lib文件。该lib文件包含一个DLL输出的符号列表。如果要链接引用该DLL的输出符号的任何可执行模块,该lib文件是必不可少的(使用GetProcAddress除外)。

   其实导入库中并不含RVA(每个符号的相对虚拟地址),只是一些符号而已,还有关于这个lib所对应的DLL的名字等。 (这只是我现在的理解)

   那当应用程序调用一个DLL的函数时,是怎么进行的呢?(使用lib的情况下)答案是在进程的主线程开始运行之前,由加载器完成。加载器根据输入节中DLL的名字按照windows的搜索路径搜索DLL,找到后DLL映射到进程的地址空间,这时DLL中对应于输入节中的各个符号的地址就可以确定了,加载器在这个时候将地址重新填入可执行模块的输入节中,动态连接完成。

补充知识 相当的重要:

windows 的搜素路径排序

1)  可执行文件所在的目录(当前目录);

2)  Windows的系统目录(该目录可以通过GetSystemDirectory函数获得);

3)  16位的系统目录(Windows目录下的system子目录);

4)  Windows目录(该目录可以通过GetWindowsDirectory函数获得);

5)  进程当前所在的工作目录;(当单击exe运行时 进程的工作目录就是 可执行文件的 目录,而当在vs 调试时 ,进程的工作目录为 项目配置文件所在的目录 ,也就是 vs设置里的 目录)

6)  PATH环境变量中所列出的目录。

注:工作目录位于Windows目录之后,这一改变开始于Windows XP SP2之后


使用控制变量法的 实战学习

1  只是用一个源文件的简单代码:

main.cpp
//(只有一个main.cpp)#include <stdio.h>void f1();void f2();void f3();int i;int main(void){     i = 10 ;   f1();   printf("\tmain: i = %d",i);   return 0;}

注意 : fata error LNK 表示声明的函数没有定义

   点击生成中的清理解决方案清理解决方案的作用是 清理 生成的目标文件exe 和 中间文件 obj)。清空后点击重新生成解决方案生成了 目标文件 exe 和中间文件 obj

   我们可以发现 在 解决方案 配置文件目录 里 的DEBUG文件中 并没有 相应的exe生成,就说明没有链接成功生成 exe 文件。但是在 项目配置文件中的DEBUG里 我们发现了 main.obj 。这说明 编译成功了。

C语言程序设计(第二版)姚琳 人民有邮电出版社:

   利用编译器对源文件进行编译,若源文件中没有语法错误,则生成目标文件 若有语法错误 ,则不能生成目标文件 obj

   我们成功的生成了 obj文件,但是并没有 链接成功 .exe 文件。

在学习C语言的过程中 我们只要先定义使用, 没错,变量和函数(变量和函数都占据 具体的物理 地址)若是没有 定义,就不能使用。但是再 编译器 眼里只要声明了(声明是指 告诉编译器 反正我定义了 ,也就是让编译器认识 声明的 字符,如果没有声明,就算定义了 编译器也不能认识 所以会报语言错误,但是至于 定义到了哪里 ,定义了没有 编译器 不管),变量和 函数 就可以编译通过生成 obj , 然而并不一定能链接 生成 exe。

简单的例子:

只有自己编写的函数

main.cpp

#include <stdio.h>int a;int main(void){int d;void f1();void f2();a = 10;int b = 1 ,c =10;a = b + c;f2();f1();scanf("%d",&d);return 0;}void f1(){a++;printf("f1: a=%d",a);}


f2.cpp

#include<stdio.h>extern int i ;    // 只是声明了 i是一个在外部已经定义过的外部变量,从而下面出现的 i 都可以放心的编译void f2(){    i =30 ;printf("\nf2: i =%d\n",i);}

   结果成功的编译了,生成了.obj文件,但是.obj文件并没有链接为 .exe 文件,显示f2.obj(f2.cpp编译成功的结果)出现了问题。无法解析的外部符号----没有定义(找不到定义更为准确

使用静态链接库的实验:

转自:http://www.cnblogs.com/wb-DarkHorse/p/3184991.html

再强调一下静态库的概念:

  静态库(static library)将函数和数据编译进一个二进制文件,(相当于省略了自己编译的步骤,默认已经编译好了成obj了,就等你直接拿来链接)通常可以命名为*.lib,编译器在链接过程中,将这些二进制数据复制出来(所以我们要给出.obj的位置),并与调用库的其他模块数据组合在一起,形成最终的可执行文件,等以后使用这个可执行文件时,就不需要这个静态库的支持了。

shixian.h //头文件

extern int gVar;                 //以前没有用到,对 外部变量 gVar 的声明,
                                 //外部变量“只”可以被显示的用 extern 来声明,告诉编译器我已经定义了extern int add(int lhs, int rhs);//extern可以省略,因为函数默认作用域是externclass T{public:    T();    T(int x, int y);    int add();private:    int a;    int b;};

shixian.cpp                                 

#include "shixian.h"            //.h写声明(声明不再内存中占据存储空间),而定义(变量或者实现都会在内存占据空间)int gVar = 10;                  // 对gVar的正式定义,因为是外部变量所以在编译期间就会被 赋值为                                 //10 ,不想 自动变量在 运行(生成.exe后才申请内存)int add(int lhs, int rhs){    return lhs + rhs;}T::T():a(0),b(0) {}T::T(int x, int y):a(x),b(y) {}int T::add(){    return a+b;}

将生成的 lib (包含了函数整套的实现,且文件名和他的工程名字一样)和 原来的.h(只用来用来编译用)放在test的工程文件下。
test.cpp

#include <iostream>#include "shixian.h"#pragma comment(lib,"lib.lib")   //直接写名字,就在工作空间查找对应的名字,工作空间为 调试时候的默认 读取目录int main(int argc, char *argv[]){    T t(1,2);    std::cout<<gVar<<std::endl;    std::cout<<add(1,2)<<std::endl;    std::cout<<t.add()<<std::endl;}

   我们把lib工程中的定义文件去全部注释掉,F5,可以发现还是可以成功的生成lib, 思考原因:静态链接就是 多个.obj问价的组合,lib只是一个包装而已,只要编译没有问题就可以生成 .obj,进而生成lib 。

现在 替换 test工程文件夹中的.lib ,运行 test,报错,链接失败,错误类型和上一个小节 的 纯源代码 不写定义是一样。

下一节 对dll的测试:


 
原创粉丝点击