# 函数声明和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__,识别到是GNUCCV_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();
}

更多关于编译相关的配置就要根据不同的编译器来具体学习了。

(adsbygoogle = window.adsbygoogle || []).push({});

1.https://stackoverflow.com/questions/34495206/whats-a-macro-before-a-function-or-a-class-in-c (opens new window)