# 函数声明和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();
}
更多关于编译相关的配置就要根据不同的编译器来具体学习了。