まず、ライブラリは何ですか
ライブラリを使用すると、コードが書かれて再利用することができ、成熟し、既存のです。実際には、すべてのプログラムは、ライブラリの多くの基本的な基盤ではなく、最初からすべての人のコードに依存するため、異例の意義ライブラリがあります。
本質的にライブラリは、オペレーティングシステムが実行するためにメモリにロードすることができ、実行可能なバイナリコードの形態です。静的ライブラリ(.Aまたは.libファイル)と動的ライブラリ(.soはまたは.dll):ライブラリーには2つのタイプがあります。
いわゆる静的、動的リンクを指します。プログラムが実行可能なプログラムステップにコンパイルされていることを思い出してください。
第二に、静的ライブラリは何ですか
[]持っているが、静的ライブラリとなり、リンク段階ので、ライブラリを参照して生成された.oオブジェクトファイルは、実行可能ファイルへのリンクが充填されたコンパイルされます。したがって、対応するリンクは、静的リンクと呼ばれます。
静的ライブラリを想像し、実行可能ファイルに一緒にコンパイル結果のオブジェクトファイルをリンクする、静的ライブラリは、.oファイル形式と類似していなければなりません。実際には、静的ライブラリは、オブジェクト・ファイル(.oの/の.objファイル)、対象ファイルの多くは圧縮パッケージ形態た後で、ファイルの簡単なコレクションの集合とみなすことができます。静的ライブラリはまとめています:
- リンクされたライブラリの静的ライブラリはコンパイル時完了時にあります。
- 接続なしでのランタイムライブラリのプログラムは、移植を容易にします。
- 関係するすべてのオブジェクトファイルやライブラリを1つの実行可能ファイルにリンクされているため、スペースとリソースの無駄。
次のようにヘッダーファイルと他の人に静的ライブラリにコンパイルされる次の単純な四則C ++クラスを書きます
#pragma once
class StaticMath
{
public:
StaticMath(void);
~StaticMath(void);
static double add(double a, double b);//加法
static double sub(double a, double b);//减法
static double mul(double a, double b);//乘法
static double div(double a, double b);//除法
void print();
};
インクルードpragma once
ファイルステートメントが一度だけコンパイルされ、ヘッダと#ifndef... #define... #endif
効果は同じです。
第三に、Windowsでの静的ライブラリを作成して使用
3.1静的ライブラリの作成します
あなたはVSコマンドラインを使用している場合だけでなく、プログラムを生成するための2つのステップでは、静的ライブラリを生成します。
- まず、/ CL.EXEのCコンパイルされたコード(CL / C StaticMath.cpp)とのコンパイラオプションを使用することによって、の「StaticMath.obj」という名前のターゲットファイルを作成します。
- 次に、(StaticMath.obj LIB)ライブラリマネージャーLIB.EXEリンクコードを使用する静的ライブラリStaticMath.libを作成します。
もちろん、我々は一般的に、より便利な設定VSプロジェクトを使用し、これを使用しないでください。あなたは、Win32コンソールアプリケーションを作成すると、静的ライブラリの種類を確認し、プロジェクトを開き、「プロパティパネル」→「構成プロパティ」→「全般」、構成タイプの静的ライブラリを選択します。
静的ライブラリを生成するプロジェクトをコンパイルします。
3.2静的ライブラリ
Win32コンソールテストプログラムを作成します。
#include "StaticMath.h"
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
double a = 10;
double b = 2;
cout << "a + b = " << StaticMath::add(a, b) << endl;
cout << "a - b = " << StaticMath::sub(a, b) << endl;
cout << "a * b = " << StaticMath::mul(a, b) << endl;
cout << "a / b = " << StaticMath::div(a, b) << endl;
StaticMath sm;
sm.print();
system("pause");
return 0;
}
使用の3種類があります。
この方法の一つ:
これは、最も一般的に使用される方法です。
- 「プロパティ]パネル」→「構成プロパティ」→「リンカ」→「一般」ディレクトリの入力追加の依存関係、静的ライブラリディレクトリ。
- 「プロパティパネル」→「構成プロパティ」→「リンカ」→「入力」は、追加の静的ライブラリの依存関係がStaticLibrary.libの名前を入力します。
コンパイルして実行OK。
方法2:
プロジェクト「プロパティパネル」→「構成プロパティ」→「リンカ」→「コマンドライン」を開き、あなたは静的ライブラリの完全なパスを入力することができます。
方法3:
プロジェクトの「プロパティパネル」→「一般プロパティ」→「フレームワークおよびリファレンス」→「参照の追加」ダイアログボックス「参照の追加」。「プロジェクト」タブにリスト各プロジェクトの現在のソリューションと同様に参照することができるすべてのライブラリ。「プロジェクト」タブでは、StaticLibraryを選択し、「OK」をクリックします。
StaticMath.hヘッダファイルのディレクトリを追加し、あなたはパスが含まれているディレクトリを変更する必要があります。プロジェクト「プロパティパネル」→「構成プロパティ」→「C / C ++」→「一般」、属性値が「追加のインクルードディレクトリ」を開き、ディレクトリへのパスStaticMath.hヘッダファイルのディレクトリやブラウズを入力します。
第四に、動的ライブラリは何ですか
上記の説明を通して、なぜあなたは、動的ライブラリにそれが必要なのか、簡単に使用することに、その静的ライブラリを発見し、理解するだけでなく、コードの再利用の目的を達成するために?
なぜ我々は、静的ライブラリは、リードの実際の特性である、動的ライブラリが必要です。
スペースの無駄が発行静的ライブラリです。
もう一つの問題は、プログラムへの展開静的データベースの更新で、ページはトラブルをもたらすでしょう公開します。静的ライブラリliba.libは更新した場合は、そのアプリケーションの使用をユーザに発行、再コンパイルする必要があるので、(プレーヤーのために、それは小さな変更かもしれませんが、それは再ダウンロードプログラム全体、更新の総量につながります)。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
动态库特点总结:
- 动态库把对一些库函数的链接载入推迟到程序运行的时期。
- 可以实现进程之间的资源共享。(因此动态库也称为共享库)
- 将一些程序升级变得简单。
- 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。
Window 与 Linux 执行文件格式不同,在创建动态库的时候有一些差异。
- 在 Windows 系统下的执行文件格式是 PE 格式,动态库需要一个 DllMain 函数做出初始化的入口,通常在导出函数的声明时需要有 _declspec(dllexport)关 键字。
- Linux 下 gcc 编译的执行文件默认是 ELF 格式,不需要初始化入口,亦不需要函数做特别的声明,编写比较方便。
五、Windows 下创建与使用动态库
5.1 创建动态库
与 Linux 相比,在 Windows 系统下创建动态库要稍微麻烦一些。首先,需要一个 DllMain 函数做出初始化的入口(创建 win32 控制台程序时,勾选 DLL 类型会自动生成这个文件):
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
通常在导出函数的声明时需要有 _declspec(dllexport) 关键字:
#pragma once
class DynamicMath
{
public:
__declspec(dllexport) DynamicMath(void);
__declspec(dllexport) ~DynamicMath(void);
static __declspec(dllexport) double add(double a, double b);//加法
static __declspec(dllexport) double sub(double a, double b);//减法
static __declspec(dllexport) double mul(double a, double b);//乘法
static __declspec(dllexport) double div(double a, double b);//除法
__declspec(dllexport) void print();
};
生成动态库需要设置工程属性,打开工程 “属性面板” → ”配置属性” → ”常规”,配置类型选择动态库。
编译项目即可生成动态库。
5.2 使用动态库
创建 Win32 控制台测试程序:
#include "stdafx.h"
#include "DynamicMath.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
double a = 10;
double b = 2;
cout << "a + b = " << DynamicMath::add(a, b) << endl;
cout << "a - b = " << DynamicMath::sub(a, b) << endl;
cout << "a * b = " << DynamicMath::mul(a, b) << endl;
cout << "a / b = " << DynamicMath::div(a, b) << endl;
DynamicMath dyn;
dyn.print();
system("pause");
return 0;
}
有 2 种使用方法:
方法一:
“属性面板” → ”配置属性” → “链接器” → ”常规”,附加依赖库目录中输入,动态库所在目录;
“属性面板” → ”配置属性” → “链接器” → ”输入”,附加依赖库中输入动态库编译出来的 DynamicLibrary.lib。
编译运行 OK。
这里可能大家有个疑问,动态库怎么还有一个 DynamicLibrary.lib 文件?即无论是静态链接库还是动态链接库,最后都有 lib 文件,那么两者区别是什么呢?其实,两个是完全不一样的东西。
StaticLibrary.lib 的大小为 190KB,DynamicLibrary.lib 的大小为 3KB,静态库对应的 lib 文件叫静态库,动态库对应的lib文件叫【导入库】。实际上静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。
方法二:
工程 “属性面板” → “通用属性” → “框架和引用” → ”添加引用”,将显示 “添加引用” 对话框。“项目” 选项卡列出了当前解决方案中的各个项目以及可以引用的所有库。 在 “项目” 选项卡中,选择 DynamicLibrary,单击 “确定”。
添加 DynamicMath.h 头文件目录,必须修改包含目录路径。打开工程 “属性面板” → ”配置属性” → “C/C++” → ” 常规”,在 “附加包含目录” 属性值中,键入 DynamicMath.h 头文件所在目录的路径或浏览至该目录。
六、在 Windows 下显式调用动态库
应用程序必须进行函数调用以在运行时显式加载 DLL。为显式链接到 DLL,应用程序必须:
- 调用 LoadLibrary(或相似的函数)以加载 DLL 和获取模块句柄。
- 调用 GetProcAddress,以获取指向应用程序要调用的每个导出函数的函数指针。由于应用程序是通过指针调用 DLL 的函数,编译器不生成外部引用,故无需与导入库链接。
- 使用完 DLL 后调用 FreeLibrary。
对 C++ 来说,情况稍微复杂。显式加载一个 C++ 动态库的困难一部分是因为 C++ 的 name mangling;另一部分是因为没有提供一个合适的 API 来装载类,在 C++ 中,您可能要用到库中的一个类,而这需要创建该类的一个实例,这不容易做到。
name mangling 可以通过 extern “C” 解决。C++ 有个特定的关键字用来声明采用 C binding 的函数:extern “C” 。用 extern “C” 声明的函数将使用函数名作符号名,就像 C 函数一样。因此,只有非成员函数才能被声明为 extern “C”,并且不能被重载。尽管限制多多,extern “C” 函数还是非常有用,因为它们可以象 C 函数一样被 dlopen 动态加载。冠以 extern “C” 限定符后,并不意味着函数中无法使用 C++ 代码了,相反,它仍然是一个完全的 C++ 函数,可以使用任何 C++ 特性和各种类型的参数。
另外如何从 C++ 动态库中获取类,附上几篇相关文章,但我并不建议这么做:
- 《LoadLibrary调用DLL中的Class》:http://www.cppblog.com/codejie/archive/2009/09/24/97141.html
- 《C++ dlopen mini HOWTO》:http://blog.csdn.net/denny_233/article/details/7255673
“显式” 使用 C++ 动态库中的 Class 是非常繁琐和危险的事情,因此能用 “隐式” 就不要用 “显式”,能静态就不要用动态。
七、总结
二者的不同点在于代码被载入的时刻不同。
- 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。
- 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小。
静的コンパイラ:実行可能ファイルをコンパイルするコンパイラは、実行可能ファイルの実行には、実行可能ファイルを有効にするために実行可能ファイルにリンクされ抽出されたセクションの対応する静的ライブラリ(.Aまたは.libファイル)を、呼び出す必要があります時間がダイナミックリンクライブラリに依存しません。
動的コンパイル:実行可能ファイルが必要で、ダイナミックリンクライブラリが付属しています(.soがまたは.dll)、実行されたときに、対応するダイナミックリンクライブラリコマンドを呼び出します。
- 長所:1、他のシステムリソースを節約し、コンパイル速度をスピードアップするためにある、実行可能ファイル自体のサイズを小さくしています。
- 短所:最初に、それは非常に簡単な手順であったとしても、ちょうど2つのコマンドでリンクライブラリを使用し、また、比較的大きなライブラリーの必要性が付属しています。そして第二に、別のコンピュータにインストールされている該当するランタイムがない場合は、その後、動的コンパイルを使用します実行可能ファイルが実行されません。
Windowsでのみライブラリを作成して使用するためにここに導入され、Linuxは無料、その後まとめた後、一時的に必要とします。
参考:
[C / C ++開発] C ++の静的および動的ライブラリとLinuxおよびWindows上で作成します