C/C++中空宏定义的作用及LLVM可见性属性相关疑问
关于LLVM中
LLVM_EXTERNAL_VISIBILITY宏的疑问 我在LLVM代码库中看到这段代码:
class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject, public ilist_node<Function> {
通过clangd查到该宏的定义如下:
/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked /// into a shared library, then the class should be private to the library and /// not accessible from outside it. Can also be used to mark variables and /// functions, making them private to any shared library they are linked into. /// On PE/COFF targets, library visibility is the default, so this isn't needed. /// /// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with /// this attribute will be made public and visible outside of any shared library /// they are linked in to. #if __has_attribute(visibility) && \ (!(defined(_WIN32) || defined(__CYGWIN__)) || \ (defined(__MINGW32__) && defined(__clang__))) #define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden"))) #if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS) #define LLVM_EXTERNAL_VISIBILITY __attribute__((visibility("default"))) #else #define LLVM_EXTERNAL_VISIBILITY // <-------------- THIS #endif #else #define LLVM_LIBRARY_VISIBILITY #define LLVM_EXTERNAL_VISIBILITY #endif
我有两个疑问:
- 为什么要定义无值的标识符,却像有值一样使用它?我的猜想是它起到条件作用:满足条件时预处理器替换为文本,否则不替换,但避免编译器报未定义标识符的错误,这是否正确?
- 这里可指定哪些属性?是否与类的链接特性相关?
解答
1. 无值宏的作用
你的猜想完全正确。这是C/C++预处理器的常用技巧:
- 当满足特定编译条件(比如构建LLVM动态库时),
LLVM_EXTERNAL_VISIBILITY会被替换为__attribute__((visibility("default"))),给类/函数加上链接可见性属性; - 不满足条件时,宏被定义为空,预处理器会直接移除代码中的
LLVM_EXTERNAL_VISIBILITY标记,既不影响代码逻辑,又能避免因宏未定义导致的编译错误。
这种写法让同一份代码能自动适配不同编译配置,无需手动修改属性标记。
2. 属性与链接特性的关系
这里用到的是GCC/Clang的可见性属性,和类、函数的链接特性直接相关:
visibility("hidden"):标记的符号(类、函数、变量)仅在当前共享库内部可见,外部无法引用,能缩小动态库的符号表规模,减少符号冲突风险;visibility("default"):标记的符号保持默认的公共可见性,允许外部代码从共享库中引用,这正是LLVM_EXTERNAL_VISIBILITY的核心作用——确保类在动态库构建场景下能被外部访问。
另外,宏定义中的条件判断也考虑了平台差异:Windows(PE/COFF)平台的默认符号可见性规则与类Unix系统不同,因此这些平台下会直接将宏定义为空,无需额外添加属性。
内容的提问来源于stack exchange,提问作者Alessandro Bertulli
相关产品推荐
相关产品推荐

