Cracking C++(2): 编译期查询编译器支持的C++标准

1. 目的

在2023年, hackingcpp 推荐用 C++20, 至少要用 C++17. 那么我的编译器是否支持 C++20 或 C++17 呢? 怎样查询我的编译器支持的 C++ 标准的版本呢?

2. 让编译器说出支持的 C++ 版本

这里以 AppleClang 编译器为例。MacOSX 自带了 Clang, 俗称 AppleClang。

创建一个空的 cpp 文件, 然后欺骗 clang 编译器说, 请用 dummy 这个 C++ 标准编译它。 clang 会发晕, 告诉你说, 我只支持这些C++标准: c++98, c++11, c++14, c++17, c++20, c++2b

➜  C_C++ git:(main) ✗ clang++ --version
Apple clang version 13.1.6 (clang-1316.0.21.2.5)
Target: x86_64-apple-darwin21.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
➜  C_C++ git:(main)touch dummy.cpp             
➜  C_C++ git:(main) ✗ clang++ -std=dummy dummy.cpp
error: invalid value 'dummy' in '-std=dummy'
note: use 'c++98' or 'c++03' for 'ISO C++ 1998 with amendments' standard
note: use 'gnu++98' or :'gnu++03' for 'ISO C++ 1998 with amendments and GNU extensions' standard
note: use 'c++11' for 'ISO C++ 2011 with amendments' standard
note: use 'gnu++11' for 'ISO C++ 2011 with amendments and GNU extensions' standard
note: use 'c++14' for 'ISO C++ 2014 with amendments' standard
note: use 'gnu++14' for 'ISO C++ 2014 with amendments and GNU extensions' standard
note: use 'c++17' for 'ISO C++ 2017 with amendments' standard
note: use 'gnu++17' for 'ISO C++ 2017 with amendments and GNU extensions' standard
note: use 'c++20' for 'ISO C++ 2020 DIS' standard
note: use 'gnu++20' for 'ISO C++ 2020 DIS with GNU extensions' standard
note: use 'c++2b' for 'Working draft for ISO C++ 2023 DIS' standard
note: use 'gnu++2b' for 'Working draft for ISO C++ 2023 DIS with GNU extensions' standard

3. 通过代码打印 C++ 版本

3.1 打印 __cplusplus 宏

由于编译阶段可以指定不同的 -std=xxx 参数, 不同的参数下, 得到的C++标准不一样。举例说, AppleClang 13 支持 C++20, 但是也可以让它以 C++11 标准执行编译。

AppleClang

对于 GCC / Clang 编译器, 可以打印 __cplusplus 宏。 这里仍然以 AppleClang 为例, 执行具体打印

// dummy.cpp
#include <iostream>

void print_cpp_std_version()
{
    std::cout << __cplusplus << std::endl;
}

int main()
{
    print_cpp_std_version();
    return 0;
}

结果如下:

➜  C_C++ git:(main) ✗ clang++ dummy.cpp 
./a     %                                                                                                                                                     
➜  C_C++ git:(main) ✗ ./a.out 
199711
➜  C_C++ git:(main) ✗ clang++ dummy.cpp -std=c++98
➜  C_C++ git:(main) ✗ ./a.out                     
199711
➜  C_C++ git:(main) ✗ clang++ dummy.cpp -std=c++11
➜  C_C++ git:(main) ✗ ./a.out                     
201103
➜  C_C++ git:(main) ✗ clang++ dummy.cpp -std=c++14
➜  C_C++ git:(main) ✗ ./a.out                     
201402
➜  C_C++ git:(main) ✗ clang++ dummy.cpp -std=c++17
➜  C_C++ git:(main) ✗ ./a.out                     
201703
➜  C_C++ git:(main) ✗ clang++ dummy.cpp -std=c++20
➜  C_C++ git:(main) ✗ ./a.out                     
202002
➜  C_C++ git:(main) ✗ clang++ dummy.cpp -std=c++2b
➜  C_C++ git:(main) ✗ ./a.out                     
202101
MSVC

原本打算在 godbolt.org 这个在线编译器上执行上述 dummy.cpp, 但此时无法执行程序, 于是改为编译器打印 __cplusplus 宏的取值。

#include <iostream>

#define XSTR(x) STR(x)
#define STR(x) #x

void print_cpp_std_version()
{
#pragma message(XSTR(__cplusplus))

}

int main()
{
    print_cpp_std_version();
    return 0;
}

使用的是 x64 msvc v19.latest 编译器, 打印结果分别为:

  • 不指定C++标准:
  • /std:c++14: 199711L
  • /std:c++17: 199711L // MSVC 的 bug。
  • /std:c++20: 199711L
  • /std:c++latest: 199711L
  • /Zc:__cplusplus: 201402L // https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
  • /Zc:__cplusplus /std:c++17: 201703L
  • /Zc:__cplusplus /std:c++20: 202002L

4. 最终代码

#include <iostream>

#define XSTR(x) STR(x)
#define STR(x) #x

void print_cpp_std_version()
{
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) || __cplusplus >= 202002L)
    #pragma message("C++20 or higher")
#elif ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
    #pragma message("C++17")
#elif ((defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) || __cplusplus >= 201402L)
    #pragma message("C++14")
#elif (__cplusplus >= 201103)
    #pragma message("C++11")
#elif (__cplusplus >= 199711L)
    #pragma message("C++03")
#else
    #pragma message "unknown C++ standard"
#endif
}

int main()
{
    print_cpp_std_version();
    return 0;
}

5. References

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值