# 函数声明和class
后的宏的作用
# 问题来源
在学习OpenCV
源码的时候,经常遇到在函数声明前和class
后面经常使用宏的情况,
// 函数声明前面使用的宏定义
CV_WRAP virtual void setVariationalRefinementAlpha(float val) = 0;
// class后面使用的宏定义
class CV_EXPORTS_W DISOpticalFlow : public DenseOpticalFlow
{
}
这个是有什么样的作用呢?
不管这个宏的位置在哪里,它都依然是宏,在预处理阶段都会被替换成宏对应的语句。
所以,要看在这些位置的宏有什么用,还是要看宏对应的内容是什么。
# 解释
出现在这些位置的宏有几个作用,
- 当宏中没有定义的内容时,可能只是起到标记的作用,便于在源码中识别
- 根据不同的平台,配置不同的编译选项。
以上面的CV_EXPORTS
为例,其定义的内容如下:
#ifndef CV_EXPORTS
#if (defined _WIN32 || defined WINCE || defined __CYGWIN__) && defined(CVAPI_EXPORTS)
#define CV_EXPORTS __declspec(dllexport)
#elif defined __GNUC__ && __GNUC__ >= 4 && (defined(CVAPI_EXPORTS) || defined(__APPLE__))
#define CV_EXPORTS __attribute__((visibility("default")))
#endif
#endif
windows
平台下编译器会定义_WIN32
,识别到是windows
平台,CV_EXPORTS
等价于__declspec(dllexport)
,这是告诉编译器,导出的是dll
库,可以据此进行优化。
linux
平台下GNUC
编译器会定义__GNUC__
,识别到是GNUC
时CV_EXPORTS
等价于__attribute__((visibility ("default")))
,这就是告诉编译器,共享文件导出的符号可见性是default
.
在Linux下动态库(.so)中,通过GCC的C++ visibility属性可以控制共享文件导出符号。在GCC 4.0及以上版本中,visibility
属性可以应用到函数、变量、模板以及C++类。
限制符号可见性的原因:从动态库中尽可能少地输出符号是一个好的实践经验。输出一个受限制的符号会提高程序的模块性,并隐藏实现的细节。动态库装载和识别的符号越少,程序启动和运行的速度就越快。导出所有符号会减慢程序速度,并耗用大量内存。
实际中有很多可以定义的编译器优化选项,使得代码工程能支持不同的平台,设置不同的编译优化方法。
如一个库更新时会把某些类和函数标记为deprecated
,就可以通过在GNC
编译时设置__attribute__((deprecated))
,在WIN
下设置__declspec(deprecated)
来实现,如下:
#if(defined WIN32 || defined _WIN32 || defined WINCE || defined __CYGWIN__)
#define MACRO_MARKER __declspec(deprecated)
#elif __GNUC__ && __GNUC__ >= 4
#define MACRO_MARKER __attribute__((deprecated))
#else
#define MACRO_MARKER
#endif
//使用
MACRO_MARKER static constexpr void testMacro() { }
编译的时候,就会提示deprecated
,
# /xx/data/code/basic_cplusplus_examples/app/main.cpp:30:21: warning: ‘constexpr void test::testMacro()’ is deprecated [-Wdeprecated-declarations]
# 30 | test::testMacro();
其实,很多库中都会使用这种用法,如TensoRT
中,
//!
//! \brief Get the padding of the convolution. If the padding is asymmetric, the pre-padding is returned.
//!
//! \see setPadding()
//!
//! \deprecated Superseded by getPaddingNd. Deprecated prior to TensorRT 8.0 and will be removed in 9.0
//!
TRT_DEPRECATED DimsHW getPadding() const noexcept
{
return mImpl->getPadding();
}
更多关于编译相关的配置就要根据不同的编译器来具体学习了。