部分参考自:https://blog.csdn.net/fengbingchun/article/details/78825004
仅作学习记录
文章目录
前置知识
1. 条件编译
具体请阅读 blog
条件编译
(conditional compiling)命令指定预处理器依据特定的条件来判断保留或删除某段源代码。
例如,可以使用条件编译让源代码适用于不同的目标系统,而不需要管理该源代码的各种不同版本。
2. 动态库.dll/.so 与 静态库.lib/.a的区别
具体请阅读 blog
在编写算法组件时,如果给业务集成人员提供 公共头文件 和 动态算法库:
- 代码组件在
linux
下编译,提供.so
,则在public头文件中的对外 函数声明上,无需加 关键字去修饰
,因为linux下的动态库接口全是对外开放的
; - 代码组件在
windows
下编译,提供.dll
, 则要在public头文件中的 函数声明上,加上EXPORT关键字
,表明该接口是对外可被调用的
;//Dll导出支持 #define EXPORT __declspec(dllexport)
3. extern "C"解释
具体请阅读 blog
使用 C 和 C++ 进行混合编程时,考虑到对函数名的处理方式不同,势必会造成编译器在程序链接阶段无法找到函数具体的实现,导致链接失败。
extern “C” 既可以修饰一句 C++ 代码,也可以修饰一段 C++ 代码,它的功能是让编译器以处理 C 语言代码的方式来处理修饰的 C++ 代码。
void Swap(int a, int b) 会被重命名为_Swap_int_int;
C编译后,函数名变为 _Swap
C++编译后,因为有重载语法的原因,函数名变为 _Swap_int_int
大白话阐述:
就是C编写的函数,按c++的编译规则 编译出的名字 和 C编出来的不同,导致在c++代码里调用C函数是找不到。
加了extern “C”{ … }后,让 其包含的内容 也按照C语言的方式编译。
#ifdef __cplusplus //如果是c++代码 {}内按照C来编译,不是就正常编译
extern "C" {
#endif
void display();
...其他声明...
#ifdef __cplusplus
}
#endif
4. C/C++中一些预定义宏
具体请阅读 blog
__declspec(dllexport)具体阐述
1. 概念解释
__declspec是Microsoft VC中专用的关键字,它配合着一些属性可以对标准C/C++进行扩充。__declspec关键字应该出现在声明的前面
。
__declspec(dllexport)
用于Windows中的动态库中
,声明导出函数、类、对象等供外面调用,省略给出.def文件
。即将函数、类等声明为导出函数,供其它程序调用,作为动态库的对外接口函数、类等。
.def文件
(模块定义文件)是包含一个或多个描述各种DLL属性的Module语句的文本文件
。.def文件或__declspec(dllexport)都是将公共符号导入到应用程序或从DLL导出函数。如果不提供__declspec(dllexport)导出DLL函数,则DLL需要提供.def文件。
__declspec(dllimport)
用于Windows中,从别的动态库中声明导入函数、类、对象等供本动态库或exe文件使用
。当你需要使用DLL中的函数时,往往不需要显示地导入函数,编译器可自动完成。不使用__declspec(dllimport)也能正确编译代码,但使用__declspec(dllimport)使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于DLL中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨DLL边界的函数调用中。声明一个导入函数,是说这个函数是从别的DLL导入。一般用于使用某个DLL的exe中。
2. 代码示例
此语法只用于 windows 下的动态库编写。
以下是测试代码:新建一个动态库工程Library,然后在CppBaseTest工程中调用Library的接口:
- library.hpp
#ifndef FBC_LIBRARY_LIBRARY_HPP_
#define FBC_LIBRARY_LIBRARY_HPP_
// reference: http://geoffair.net/ms/declspec.htm
#ifdef _MSC_VER
#ifdef FBC_STATIC
#define FBC_API
#elif defined FBC_EXPORT
#define FBC_API __declspec(dllexport)
#else
#define FBC_API __declspec(dllimport)
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
FBC_API int library_add(int a, int b);
FBC_API int value;
#ifdef __cplusplus
}
#endif
template<typename T>
class FBC_API Simple {
public:
Simple() = default;
void Init(T a, T b);
T Add() const;
private:
T a, b;
};
#endif // FBC_LIBRARY_LIBRARY_HPP_
- library.cpp
#include "library.hpp"
#include <iostream>
#include <string>
FBC_API int library_add(int a, int b)
{
value = 11;
fprintf(stdout, "File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__);
return (a+b);
}
template<typename T>
void Simple<T>::Init(T a, T b)
{
this->a = a;
this->b = b;
}
template<typename T>
T Simple<T>::Add() const
{
fprintf(stdout, "File: %s, Function: %s, Line: %d\n", __FILE__, __FUNCTION__, __LINE__);
return (a + b);
}
template class Simple<int>;
template class Simple<std::string>;
- test_library.hpp
#ifndef FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_
#define FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_
#include <library.hpp>
namespace test_library_ {
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllimport) int library_add(int, int);
__declspec(dllimport) int value;
#ifdef __cplusplus
}
#endif
int test_library_1();
int test_library_2();
} // namespace test_library_
#endif // FBC_CPPBASE_TEST_TEST_LIBRARY_HPP_
- test_library.cpp
#include "test_library.hpp"
#include <iostream>
#include <string>
#include <library.hpp>
namespace test_library_ {
int test_library_1()
{
int a{ 4 }, b{ 5 }, c{ 0 };
c = library_add(a, b);
fprintf(stdout, "%d + %d = %d\n", a, b, c);
fprintf(stdout, "value: %d\n", value);
return 0;
}
int test_library_2()
{
Simple<int> simple1;
int a{ 4 }, b{ 5 }, c{ 0 };
simple1.Init(a, b);
c = simple1.Add();
fprintf(stdout, "%d + %d = %d\n", a, b, c);
Simple<std::string> simple2;
std::string str1{ "csdn blog: " }, str2{ "http://blog.csdn.net/fengbingchun" }, str3;
simple2.Init(str1, str2);
str3 = simple2.Add();
fprintf(stdout, "contents: %s\n", str3.c_str());
return 0;
}
} // namespace test_library_
注意理解library.hpp中FBC_API的条件编译可以表示静态链接库接口、动态链接库导出接口、动态链接库导入接口,通过VS中预编译宏(配置属性->C/C+±>预处理器->预处理器定义)的定义来实现不同的功能;