clang编译器 abseil-cpp中的ABSL_MUST_USE_RESULT
最近在看google的abseil-cpp
,代码仓库地址为https://github.com/abseil/abseil-cpp
仓库使用的协议为Apache-2.0
abseil-cpp是一个开源的 C++ 库,由 Google 开发,提供了一系列工具和抽象来增强 C++ 代码的健壮性和可移植性
现在是2025-09-25 20:55,当前abseil-cpp代码库master分支最新提交的id为
473a0c7530afb9ca5d107a64a3de46f84be757b5
abseil-cpp项目可以使用cmake和g++编译,但是使用clang编译可以“激活”一些隐藏功能(下文单开一个小标题细说一个点)
首先安装clang
sudo apt-get install clang
安装好后写一个最简单的hello, world
程序都提示iostream file not found
,查阅资料发现clang是一个可插拔的组件式的编译器,而g++是一个开箱即用
查阅资料后首先安装了libc+±dev
sudo apt-get install libc++-dev
但是依旧
再次安装g+±12就可以正常编译了
sudo apt-get install g++-12
后面在论坛帖子 Clang can’t find iostream找到了答案,截个图
大概意思是,clang和clang++其实是在借用gcc和g++中的头文件。当安装了多个版本的gcc和g++的版本时,它会自动选择最新的版本
所以总结一下,我一开始提示找不到iostream
的原因:linux系统同时安装了gcc11和gcc12,编译时选择最新的版本,于是选择了gcc12和g++12。但是电脑没有安装g+±12,所以iostream
找不到
使用clang
编译这个项目,首先cmake生成需要使用命令(在build目录下)
CC=clang CXX=clang++ cmake ..
然后发现需要使用C++17,否则无法编译通过
CC=clang CXX=clang++ cmake -D CMAKE_CXX_STANDARD=17 ..
接下来make编译即可
clang 编译器编译 abseil-cpp 激活“隐藏功能”之ABSL_MUST_USE_RESULT
ABSL_MUST_USE_RESULT
宏用于修饰一个函数,比如
ABSL_MUST_USE_RESULT int test() {return 42;
}
MUST USE RESULT
即必须使用结果。当函数的结果未被使用时,比如
ABSL_MUST_USE_RESULT int test() {return 42;
}int main() {test();return 0;
}
编译时会给出警告
ABSL_MUST_USE_RESULT
原理
// Copyright 2017 The Abseil Authors.#if !defined(__has_attribute)
#define __has_attribute(x) 0
#endif#ifdef __has_attribute
#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
#else
#define ABSL_HAVE_ATTRIBUTE(x) 0
#endif#if defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
#else
#define ABSL_MUST_USE_RESULT
#endif
大伙可能被这一堆代码吓坏了(反正我被吓坏了doge)
其实这一堆代码是考虑了某些编译器不支持的情况,比如g++编译器就不支持
对于clang编译器把核心摘出来就是
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
也就是说,由编译器实现检查一个被ABSL_MUST_USE_RESULT宏修饰的函数的返回值是否被忽略
对于clang编译器(即定义了__clang__
属性),还会检查是否有__has_attribute
,它用于检查是否支持其他属性;如果没有那就不支持ABSL_MUST_USE_RESULT
宏,如果有,通过__has_attribute
宏检查是否支持warn_unused_result
,它最终实现了检查一个被ABSL_MUST_USE_RESULT宏修饰的函数的返回值是否被忽略
如果没有__has_attribute
或者不支持warn_unused_result
,那么ABSL_HAVE_ATTRIBUTE
宏的实现为
#define ABSL_HAVE_ATTRIBUTE(x) 0
最终ABSL_MUST_USE_RESULT
宏的实现为
#define ABSL_MUST_USE_RESULT
也就是将ABSL_MUST_USE_RESULT
替换为空,从而忽略
但是测试发现g++编译器其实也可以实现该功能,于是修改代码为
#if (defined(__clang__) || defined(__GNUC__)) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
#else
#define ABSL_MUST_USE_RESULT
#endif
这样一个PR不就来了么doge
PS:一觉起来得到了官方的回复。C++17已经引入了[[nodiscard]]
来实现这一功能(PR其实没有必要QVQ)