使用Clang作为编译器 —— Clang 语言扩展

1. 介绍

本文档描述了 Clang 提供的语言扩展。除了这里列出的语言扩展之外,Clang 还旨在支持广泛的 GCC 扩展。有关这些扩展的更多信息,请参阅 GCC手册

2. 特性检查宏

语言扩展可能非常有用,但只有在您知道可以依赖它们的情况下。为了允许细粒度特性检查,我们支持三个内置类似函数的宏。这允许您直接测试代码中的某个特性,而不必求助于autoconf或脆弱的“编译器版本检查”。

2.1 __has_builtin

这个类似函数的宏只接受一个标识符参数,即一个内置函数的名称。如果支持构建,它的值为1;如果不支持,它的值为0。它可以这样使用:

#ifndef __has_builtin         // Optional of course.
  #define __has_builtin(x) 0  // Compatibility with non-clang compilers.
#endif

...
#if __has_builtin(__builtin_trap)
  __builtin_trap();
#else
  abort();
#endif
...
2.2 __has_feature 和 __has_extension

这些类似函数的宏只接受一个标识符参数,即特性的名称。在当前语言标准中,如果特性是由 Clang 支持和被标准化,__has_feature的值为1;或如果不是,它的值为0(但见下文),而在当前语言中(作为一个语言扩展或一个标准语言特性),如果特性是由 Clang 支持,__has_extension的值为1;如果不是,它的值为0。它们可以这样使用:

#ifndef __has_feature         // Optional of course.
  #define __has_feature(x) 0  // Compatibility with non-clang compilers.
#endif
#ifndef __has_extension
  #define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
#endif

...
#if __has_feature(cxx_rvalue_references)
// This code will only be compiled with the -std=c++11 and -std=gnu++11
// options, because rvalue references are only standardized in C++11.
#endif

#if __has_extension(cxx_rvalue_references)
// This code will be compiled with the -std=c++11, -std=gnu++11, -std=c++98
// and -std=gnu++98 options, because rvalue references are supported as a
// language extension in C++98.
#endif

为了向后兼容性,还可以使用_has_feature测试对非标准化特性的支持,即不带前缀c_cxx_objc_的特性。
has_feature的另一个用途是检查与语言标准无关的编译器特性,例如 AddressSanitizer
如果提供了-pedantic-errors选项,那么_has_extension等同于_has_feature
特性 tag 和下面的语言特性一起描述。
特性名或扩展名也可以用前面和后面添加__(双下划线)指定,以避免来自同名宏的干扰。例如,可以使用__cxx_rvalue_references__代替cxx_rvalue_references

2.3 __has_cpp_attribute

默认情况下,这个类似函数的宏在 C++2a 中可用,并在早期的语言标准中作为扩展提供。它接受一个参数,该参数是双方括号样式属性的名称。参数可以是单个标识符,也可以是范围标识符。如果支持该属性,则返回一个非零值。如果该属性是基于标准的属性,则该宏根据该属性投票进入工作草案的年份和月份返回一个非零值。有关基于标准的属性返回的值列表,请参见 WG21 SD-6。如果当前编译目标不支持该属性,则此宏的计算值为0。它可以这样使用:

#ifndef __has_cpp_attribute         // For backwards compatibility
  #define __has_cpp_attribute(x) 0
#endif

...
#if __has_cpp_attribute(clang::fallthrough)
#define FALLTHROUGH [[clang::fallthrough]]
#else
#define FALLTHROUGH
#endif
...

属性范围令牌clang和_Clang是可互换的,属性范围令牌gnu和_gnu__也是可互换的。这些名称空间中的任何一个中的属性标记都可以用__(双下划线)前后指定,以避免来自具有相同名称的宏的干扰。例如,gnu::_ const__可以代替gnu::const。

2.4 __has_c_attribute

这个类似函数的宏接受一个参数,该参数是在C模式下使用双方括号语法公开的属性的名称。参数可以是单个标识符,也可以是范围标识符。如果支持该属性,则返回一个非零值。如果当前编译目标不支持该属性,则此宏的计算值为0。它可以这样使用:

#ifndef __has_c_attribute         // Optional of course.
  #define __has_c_attribute(x) 0  // Compatibility with non-clang compilers.
#endif

...
#if __has_c_attribute(fallthrough)
  #define FALLTHROUGH [[fallthrough]]
#else
  #define FALLTHROUGH
#endif
...

属性范围令牌clang和_Clang是可互换的,属性范围令牌gnu和_gnu__也是可互换的。这些名称空间中的任何一个中的属性标记都可以用__(双下划线)前后指定,以避免来自具有相同名称的宏的干扰。例如,gnu::_ const__可以代替gnu::const。

2.5 __has_attribute

这个类似函数的宏接受一个标识符参数,该参数是一个GNU-style属性的名称。如果当前编译目标支持该属性,则计算为1;如果不支持,则为0。它可以这样使用:

#ifndef __has_attribute         // Optional of course.
  #define __has_attribute(x) 0  // Compatibility with non-clang compilers.
#endif

...
#if __has_attribute(always_inline)
#define ALWAYS_INLINE __attribute__((always_inline))
#else
#define ALWAYS_INLINE
#endif
...

属性名也可以用前面和后面的__(双下划线)来指定,以避免来自同名宏的干扰。例如,可以使用_always_inline__代替always_inline。

2.6 __has_declspec_attribute

这个类似函数的宏接受一个标识符参数,该参数是作为microsoft风格的_declspec属性实现的属性的名称。如果当前编译目标支持该属性,则计算为1;如果不支持,则为0。它可以这样使用:

#ifndef __has_declspec_attribute         // Optional of course.
  #define __has_declspec_attribute(x) 0  // Compatibility with non-clang compilers.
#endif

...
#if __has_declspec_attribute(dllexport)
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
...

属性名也可以用前面和后面的__(双下划线)来指定,以避免来自同名宏的干扰。例如,可以使用_dllexport__代替dllexport。

2.7 __is_identifier

这个类似函数的宏接受一个标识符参数,该参数可以是保留字,也可以是常规标识符。如果参数只是常规标识符而不是保留字,那么它的值为1,因为它可以用作用户定义的函数或变量的名称。否则它的值为0。它可以这样使用:

...
#ifdef __is_identifier          // Compatibility with non-clang compilers.
  #if __is_identifier(__wchar_t)
    typedef wchar_t __wchar_t;
  #endif
#endif

__wchar_t WideCharacter;
...

3. Include文件检查宏

不是所有的开发系统都有相同的包含文件。在执行可能失败的#include指令之前,可以使用_has_include和_has_include_next宏检查包含文件是否存在。Include文件检查宏必须用作#if或#elif预处理指令中的表达式。

3.1 __has_include

这个类似函数的宏接受一个文件名字符串参数,即包含文件的名称。如果可以使用include路径找到文件,则计算为1,否则为0:

// Note the two possible file name string formats.
#if __has_include("myinclude.h") && __has_include(<stdint.h>)
# include "myinclude.h"
#endif

要测试这个特性,请使用#if defined(_has_include)

// To avoid problem with non-clang compilers not having this macro.
#if defined(__has_include)
#if __has_include("myinclude.h")
# include "myinclude.h"
#endif
#endif
3.2 __has_include_next

这个类似函数的宏接受一个文件名字符串参数,即包含文件的名称。它类似于……has_include,只是它查找在include路径中找到的给定文件的第二个实例。如果可以使用include路径找到文件的第二个实例,则计算为1,否则为0:

// Note the two possible file name string formats.
#if __has_include_next("myinclude.h") && __has_include_next(<stdint.h>)
# include_next "myinclude.h"
#endif

// To avoid problem with non-clang compilers not having this macro.
#if defined(__has_include_next)
#if __has_include_next("myinclude.h")
# include_next "myinclude.h"
#endif
#endif

注意,与GNU extension #include_next指令一样,_has_include_next仅用于头文件中,如果在顶级编译文件中使用,则会发出警告。如果在文件参数中使用绝对路径,也会发出警告。

3.3 __has_warning

这个类似函数的宏接受一个字符串文字,它表示警告的命令行选项,如果是有效的警告选项,则返回true。

#if __has_warning("-Wformat")
...
#endif

4. 内置宏(Builtin Macros)

  • __BASE_FILE__
    定义为包含传递给Clang的主输入文件的名称的字符串。
  • `FILE_NAME``
    特定于clang的扩展,其功能类似于_ file__,但只呈现最后一个路径组件(文件名),而不是依赖于调用的文件的完整路径。
  • __COUNTER__
    定义为一个整数值,该整数值从0开始,并且在每次扩展_counter__宏时递增。
  • __INCLUDE_LEVEL__
    定义为一个整数值,即当前正在翻译的文件的包含深度。对于主文件,这个值为零。
  • __TIMESTAMP__
    定义为最近一次修改当前源文件的日期和时间。
  • __clang__
    使用Clang编译时定义
  • __clang_major__
    定义为Clang的主要营销版本号(例如2.0.1中的2)。注意,营销版本号不应该用于检查语言特性,因为不同的供应商使用不同的编号方案。相反,使用特性检查宏
  • __clang_minor__
    定义为Clang的次要版本号(例如2.0.1中的0)。注意,营销版本号不应该用于检查语言特性,因为不同的供应商使用不同的编号方案。相反,使用特性检查宏
  • __clang_patchlevel__
    定义为Clang的市场补丁级别(例如2.0.1中的1)。
  • __clang_version__
    定义为捕获Clang marketing版本的字符串,包括Subversion标记或版本号,例如“1.5 (trunk 102332)”。

5. 向量和扩展向量

支持GCC、OpenCL、AltiVec和NEON向量扩展。

OpenCL向量类型是使用ext_vector_type属性创建的。它支持V。xyzw语法和OpenCL中的其他花絮。一个例子是:

typedef float float4 __attribute__((ext_vector_type(4)));
typedef float float2 __attribute__((ext_vector_type(2)));

float4 foo(float2 a, float2 b) {
  float4 c;
  c.xz = a;
  c.yw = b;
  return c;
}

使用_has_extension(attribute_ext_vector_type)查询此特性。

为clang提供-maltivec选项支持AltiVec向量语法和函数。例如:

vector float foo(vector int a) {
  vector int b;
  b = vec_add(a, a) + a;
  return (vector float)b;
}

NEON 向量类型是使用neon_vector_type和neon_polyvector_type属性创建的。例如:

typedef __attribute__((neon_vector_type(8))) int8_t int8x8_t;
typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t;

int8x8_t foo(int8x8_t a) {
  int8x8_t v;
  v = a;
  return v;
}
5.1 向量文字(Vector Literals)

向量文字可用于从一组标量或向量创建向量。可以使用圆括号或大括号形式。在圆括号中,指定的文字值的数量必须为1,即引用标量值,或者必须匹配正在创建的向量类型的大小。如果指定单个标量文字值,则该标量文字值将复制到向量类型的所有组件。在括号中可以指定任意数量的文字。例如:

typedef int v4si __attribute__((__vector_size__(16)));
typedef float float4 __attribute__((ext_vector_type(4)));
typedef float float2 __attribute__((ext_vector_type(2)));

v4si vsi = (v4si){1, 2, 3, 4};
float4 vf = (float4)(1.0f, 2.0f, 3.0f, 4.0f);
vector int vi1 = (vector int)(1);    // vi1 will be (1, 1, 1, 1).
vector int vi2 = (vector int){1};    // vi2 will be (1, 0, 0, 0).
vector int vi3 = (vector int)(1, 2); // error
vector int vi4 = (vector int){1, 2}; // vi4 will be (1, 2, 0, 0).
vector int vi5 = (vector int)(1, 2, 3, 4);
float4 vf = (float4)((float2)(1.0f, 2.0f), (float2)(3.0f, 4.0f));
5.2 向量操作(Vector Operations)

下表显示了对每个向量扩展操作的支持。破折号表示根据相应的规范不接受操作。

OperatorOpenCLAltiVecGCCNEON
[]yesyesyes
unary operators +, –yesyesyes
++, – –yesyesyes
+,–,*,/,%yesyesyes
bitwise operators &,|,^,~yesyesyes
>>,<<yesyesyes
!, &&,yes
==, !=, >, <, >=, <=yesyes
=yesyesyesyes
:?yes
sizeofyesyesyesyes
C-style castyesyesyesno
reinterpret_castyesnoyesno
static_castyesnoyesno
const_castnononono

还请参见_builtin_shufflevector_builtin_convertvector

6. Half-Precision浮点

Clang支持两种半精度(16位)浮点类型:_fp16和_Float16。所有语言模式都支持这些类型。

每个目标都支持_fp16,因为它纯粹是一种存储格式;见下文。_Float16目前只在以下目标上受支持,还有一些目标有待ABI标准化:- 32位ARM - 64位ARM (AArch64) - SPIR _Float16将在更多的目标上受支持,因为它们为它定义了ABIs。

仅是存储和交换格式。这意味着当在算术运算中使用时,会立即(至少)将……fp16的值提升为浮点数,因此,例如,添加两个……fp16值的结果具有float类型。_fp16的行为由ARM C语言扩展(ACLE)指定。Clang使用来自IEEE 754-2008的二进制16格式来处理_fp16,而不是ARM的替代格式。

_Float16是一个扩展的浮点类型。这意味着,就像对float或double的运算一样,对_Float16操作数的运算也是以_Float16类型正式执行的,例如,添加两个_Float16值的结果具有_Float16类型。_Float16的行为由ISO/IEC TS 18661- 3:15(“C的浮点扩展”)指定。与使用_fp16一样,Clang对_Float16使用IEEE 754-2008中的二进制16格式。

_Float16算法将使用本机半精度支持在目标上执行(例如在ARMv8.2a上);否则,它将以更高的精度执行(当前总是浮点数),然后截断为_Float16。注意,C和c++允许计算表达式的中间浮点操作数,其精度比在它们的类型中所能表达的精度更高,因此在某些情况下,Clang可以避免中间截断;这可能导致与本机算法不一致的结果。

建议可移植代码使用_Float16而不是_fp16,因为C标准委员会已经定义了它,它的行为对大多数程序员来说更熟悉。

因为总是立即将……fp16操作数提升为float,所以对于通常的算术转换而言,常见的实际类型是float。

可以使用后缀f16指定_Float16类型;例如:’ 3.14f16 ’

因为默认参数提升只适用于标准浮点类型,所以当作为可变参数或无类型参数传递时,_Float16值不会提升为double。因此,在使用_Float16的某些库设施时必须谨慎;例如,_Float16没有printf格式说明符,而且(与float不同)它在传递给printf时不会被隐式地提升为double,所以程序员必须显式地将它转换为double,然后再使用%f或类似的说明符。
关于废弃和不可用属性的消息
可以将可选字符串消息添加到不推荐的和不可用的属性中。例如:

void explode(void) __attribute__((deprecated("extremely unsafe, use 'combust' instead!!!")));

如果使用不赞成的或不可用的声明,则该消息将并入适当的诊断:

harmless.c:4:3: warning: 'explode' is deprecated: extremely unsafe, use 'combust' instead!!!
      [-Wdeprecated-declarations]
  explode();
  ^

使用_has_extension(attribute_deprecated_with_message)_has_extension(attribute_unavailable_with_message)查询此特性。

7. 枚举成员上的属性

Clang允许在单个枚举器上编写属性。这允许不推荐枚举数,使之不可用,等等。属性必须出现在枚举器名称之后和任何初始化器之前,如下所示:

enum OperationMode {
  OM_Invalid,
  OM_Normal,
  OM_Terrified __attribute__((deprecated)),
  OM_AbortOnError __attribute__((deprecated)) = 4
};

枚举声明上的属性不适用于单个枚举数。

使用_has_extension(enumerator_attributes)查询此特性。

指定的系统框架
Clang提供了一种机制,通过这种机制可以构建框架,使它们始终被视为“系统框架”,即使它们不在系统框架目录中。对于希望能够使用框架的开发构建测试构建其他应用程序(包括编译器更改系统头的警告行为的方式)的系统框架开发人员来说,这非常有用。

框架开发人员可以通过创建“。在它们的框架的顶层的system_framework文件。也就是说,框架应该包含以下内容:

.../TestFramework.framework
.../TestFramework.framework/.system_framework
.../TestFramework.framework/Headers
.../TestFramework.framework/Headers/TestFramework.h
...

Clang将把这个文件的存在视为一个指示符,指示框架应该被视为一个系统框架,而不管它是如何在框架搜索路径中找到的。为了保持一致性,我们建议这种文件永远不要包含在框架的安装版本中。

检查标准语言特性
如果启用了某些标准语言特性,可以使用_has_feature宏来查询。在编译不提供语言特性的标准时,可以使用_has_extension宏查询语言特性是否可用作扩展。这里列出了可以测试的特性。

自Clang 3.4以来,还支持c++ SD-6特性测试宏。这些宏的名称为格式为_cpp_<feature_name>,旨在作为一种可移植的方式来查询编译器支持的特性。</feature_name>有关每个Clang版本支持的SD-6版本的信息,以及该建议修订版提供的宏,请参阅c++状态页。

C + + 98
下面列出的特性是c++ 98标准的一部分。编译c++代码时默认启用这些特性。

c++异常
使用_has_feature(cxx_exception)来确定是否启用了c++异常。例如,使用-fno-exception编译代码将禁用c++异常。

c++ RTTI
使用_has_feature(cxx_rtti)来确定是否启用了c++ RTTI。例如,使用-fno-rtti编译代码将禁用RTTI的使用。

c++ 11
下面列出的特性是c++ 11标准的一部分。因此,在编译c++代码时,所有这些特性都是使用-std=c++11或-std=gnu++11选项启用的。

c++ 11 SFINAE包含访问控制
使用_has_feature(cxx_access_control_sfinae)或_has_extension(cxx_access_control_sfinae)来确定访问控制错误(例如,调用私有构造函数)是否被认为是每个c++ DR1170的模板参数推断错误(也称为SFINAE错误)。

c++模板11别名
使用_has_feature(cxx_alias_templates)或_has_extension(cxx_alias_templates)来确定是否支持c++ 11的别名声明和别名模板。

c++ 11对齐说明符
使用_has_feature(cxx_alignas)或_has_extension(cxx_alignas)来确定是否启用了对使用alignas的对齐说明符的支持。

使用_has_feature(cxx_alignof)或_has_extension(cxx_alignof)来确定是否启用了对alignof关键字的支持。

c++ 11属性
使用_has_feature(cxx_attributes)或_has_extension(cxx_attributes)来确定是否支持使用c++ 11的方括号符号进行属性解析。

c++ 11通用常数表达式
使用_has_feature(cxx_constexpr)来确定是否支持通用常量表达式(例如,constexpr)。

c++ 11 decltype ()
使用_has_feature(cxx_decltype)或_has_extension(cxx_decltype)来确定是否启用了对decltype()说明符的支持。c++ 11的decltype不需要函数调用表达式的类型完整性。使用_has_feature(cxx_decltype_incomplete_return_types)或_has_extension(cxx_decltype_incomplete_return_types)来确定是否启用了对该特性的支持。
函数模板中的11个默认模板参数
使用_has_feature(cxx_default_function_template_args)或_has_extension(cxx_default_function_template_args)来确定是否启用了函数模板中对默认模板参数的支持。

c++ 11违约的功能
使用_has_feature(cxx_defaulted_functions)或_has_extension(cxx_defaulted_functions)来确定是否启用了对默认函数定义的支持(使用= default)。

c++ 11委托构造函数
使用_has_feature(cxx_delegating_constructors)来确定是否启用了对委托构造函数的支持。

c++ 11删除功能
使用_has_feature(cxx_deleted_functions)或_has_extension(cxx_deleted_functions)来确定是否启用了对已删除函数定义的支持(使用= delete)。

c++ 11显式转换函数
使用_has_feature(cxx_explicit_conversions)来确定是否启用了对显式转换函数的支持。

c++ 11广义初始值设定项
使用_has_feature(cxx_generalized_initialalizer)来确定是否启用了对通用初始化器的支持(使用带括号的列表和std::initializer_list)。

c++ 11隐式移动构造函数/赋值运算符
使用_has_feature(cxx_implicit_moves)来确定Clang是否会隐式地生成move构造函数,并在需要的地方生成move赋值操作符。

c++ 11继承的构造函数
使用_has_feature(cxx_inheriting_constructors)来确定是否启用了对继承构造函数的支持。

11 c++内联名称空间
使用_has_feature(cxx_inline_namespaces)或_has_extension(cxx_inline_namespaces)来确定是否启用了对内联名称空间的支持。

c++ 11λ
使用_has_feature(cxx_lambdas)或_has_extension(cxx_lambdas)来确定是否启用了对lambdas的支持。

c++ 11局部类型和未命名类型作为模板参数
使用_has_feature(cxx_local_type_template_args)或_has_extension(cxx_local_type_template_args)来确定是否支持将局部类型和未命名类型作为模板参数。

11 noexcept c++
使用_has_feature(cxx_noexcept)或_has_extension(cxx_noexcept)来确定是否启用了对noexcept异常规范的支持。

类内非静态数据成员初始化
使用_has_feature(cxx_nonstatic_member_init)来确定是否启用了非静态数据成员的类内初始化。

11 nullptr c++
使用_has_feature(cxx_nullptr)或_has_extension(cxx_nullptr)来确定是否启用了对nullptr的支持。

c++ 11覆盖控制
使用_has_feature(cxx_override_control)或_has_extension(cxx_override_control)来确定是否启用了对覆盖控件关键字的支持。

c++ 11 reference-qualified功能
使用_has_feature(cxx_reference_qualified_functions)或_has_extension(cxx_reference_qualified_functions)来确定是否启用了对引用限定函数的支持(例如,具有&或&&应用于*this的成员函数)。

基于c++ 11范围的for循环
使用_has_feature(cxx_range_for)或_has_extension(cxx_range_for)来确定是否启用了对基于范围的for循环的支持。
c++ 11原始字符串文字
使用_has_feature(cxx_raw_string_literals)来确定是否启用了对原始字符串文字的支持(例如,R"x(foo\bar)x")。

c++ 11右值引用
使用_has_feature(cxx_rvalue_references)或_has_extension(cxx_rvalue_references)来确定是否启用了对rvalue引用的支持。

c++ 11 static_assert ()
使用_has_feature(cxx_static_assert)或_has_extension(cxx_static_assert)来确定是否启用了对使用static_assert的编译时断言的支持。

11 thread_local c++
使用_has_feature(cxx_thread_local)来确定是否启用了对thread_local变量的支持。

c++ 11类型推断
使用_has_feature(cxx_auto_type)或_has_extension(cxx_auto_type)来确定使用自动说明符支持c++ 11类型推断。如果禁用此功能,auto将作为存储类说明符,如C或c++ 98中所示。

c++ 11强类型枚举
使用_has_feature(cxx_strong_enums)或_has_extension(cxx_strong_enums)来确定是否启用了对强类型、范围枚举的支持。

c++ 11尾随返回类型
使用_has_feature(cxx_trailing_return)或_has_extension(cxx_trailing_return)来确定是否启用了对带有尾随返回类型的替代函数声明语法的支持。

c++ 11 Unicode字符串文字
使用_has_feature(cxx_unicode_literals)来确定是否启用了对Unicode字符串常量的支持。

c++ 11无限制的工会
使用_has_feature(cxx_unrestricted ted_unions)来确定是否启用了对非受限联合的支持。

c++ 11用户定义的文字
使用_has_feature(cxx_user_literals)来确定是否启用了对用户定义的文字的支持。

c++ 11可变模板
使用_has_feature(cxx_variadic_templates)或_has_extension(cxx_variadic_templates)来确定是否启用了对可变参数模板的支持。

c++ 14
下面列出的特性是c++ 14标准的一部分。因此,在编译c++代码时,所有这些特性都是通过-std= c++ 14或-std=gnu++14选项启用的。

c++ 14二进制字面值
使用_has_feature(cxx_binary_literals)或_has_extension(cxx_binary_literals)来确定是否识别二进制文字(例如,0b10010)。Clang在所有语言模式中都支持此功能作为扩展。

c++ 14上下文转换
使用__has_feature (cxx_contextual_conversions)或__has_extension (cxx_contextual_conversions)来确定c++ 14当执行一个隐式转换规则是用于数组绑定在一个新的表达式,delete-expression的操作数,一个积分常数表达式,switch语句或条件。

c++ 14 decltype(汽车)
使用_has_feature(cxx_decltype_auto)或_has_extension(cxx_decltype_auto)来确定是否启用了对decltype(auto)占位符类型的支持。

用于聚合的c++ 14默认初始化器
使用_has_feature(cxx_aggregate_nsdmi)或_has_extension(cxx_aggregate_nsdmi)来确定是否支持聚合成员中的默认初始化器。

c++ 14位分隔符
使用_cpp_digit_separator来确定是否支持使用单引号的数字分隔符(例如,10,000)。此时,没有对应的_has_feature名称

c++ 14通用lambda捕获
使用_has_feature(cxx_init_capture)或_has_extension(cxx_init_capture)来确定是否启用了对带有显式初始化器的lambda capture的支持(例如,[n(0)] {return ++n;})。

c++ 14通用λ
使用_has_feature(cxx_generic_lambdas)或_has_extension(cxx_generic_lambdas)来确定是否启用了对泛型(多态)lambdas的支持(例如,[](auto x) {return x + 1;})。

c++ constexpr 14放松
使用_has_feature(cxx_relaxed_constexpr)或_has_extension(cxx_relaxed_constexpr)来确定是否允许在constexpr函数中声明变量、修改局部变量和控制流构造。

c++ 14返回类型扣除
使用_has_feature(cxx_return_type_演绎)或_has_extension(cxx_return_type_演绎)来确定是否支持函数的返回类型演绎(使用auto作为返回类型)。

c++ 14 runtime-sized数组
使用_has_feature(cxx_runtime_array)或_has_extension(cxx_runtime_array)来确定是否启用了对运行时绑定数组(可变长度数组的受限形式)的支持。Clang对该特性的实现还不完整。

c++模板14个变量
使用_has_feature(cxx_variable_templates)或_has_extension(cxx_variable_templates)来确定是否启用了对模板化变量声明的支持。

C11
下面列出的特性是C11标准的一部分。因此,在编译C代码时使用-std=c11或-std=gnu11选项启用了所有这些特性。此外,由于这些特性都是向后兼容的,所以它们可以作为所有语言模式的扩展。

C11对齐说明符
使用_has_feature(c_alignas)或_has_extension(c_alignas)来确定是否启用了对使用_Alignas的对齐说明符的支持。

使用_has_feature(c_alignof)或_has_extension(c_alignof)来确定是否启用了对_Alignof关键字的支持。

C11原子操作
使用_has_feature(c_atomic)或_has_extension(c_atomic)来确定是否启用了对使用_Atomic的原子类型的支持。Clang还提供了一组内建函数,可用于实现<stdatomic。< span="">h>对_Atomic类型的操作。使用_has_include(<stdatomic.h>)来确定C11的<stdatomic。< span="">h>报头可用。</stdatomic。<></stdatomic.h></stdatomic。<>

Clang将使用系统的<stdatomic。< span="">h>头时,一个可用,否则将使用自己的。当使用它自己的操作时,原子操作的实现作为宏提供。在C11还需要一个实函数的情况下,这个头文件只提供了该函数的声明(以及一个隐藏的宏实现),如果您使用它而不是宏,则必须链接到一个库,该库提供了函数的定义。</stdatomic。<>

C11通用的选择
使用_has_feature(c_generic_selection)或_has_extension(c_generic_selection)来确定是否启用了对泛型选择的支持。

作为扩展,C11通用选择表达式在Clang支持的所有语言中都可用。语法与C11标准中给出的相同。

在C语言中,类型兼容性是根据适当标准中给出的规则来决定的,但是在c++中,缺少C语言中使用的类型兼容性规则,只有当类型是等价的时,才会认为类型是兼容的。

C11 _Static_assert ()
使用_has_feature(c_static_assert)或_has_extension(c_static_assert)来确定是否启用了对使用_Static_assert的编译时断言的支持。

C11 _Thread_local
使用_has_feature(c_thread_local)或_has_extension(c_thread_local)来确定是否启用了对_Thread_local变量的支持。

模块
使用_has_feature(模块)来确定是否启用了模块。例如,使用-fmodules编译代码可以使用模块。

更多信息可以在这里找到。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值