__builtin_addressof

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dashuniuniu/article/details/79945154

__builtin_addressof

__builtin_addressof是由Richard Smith提交到clang中的,提交的patch为Add a __builtin_addressof that performs the same functionality as the built-in,commit message如下:

Add a __builtin_addressof that performs the same functionality as the built-in
& operator (ignoring any overloaded operator& for the type). The purpose of
this builtin is for use in std::addressof, to allow it to be made constexpr;
the existing implementation technique (reinterpret_cast to some reference type,
take address, reinterpert_cast back) does not permit this because
reinterpret_cast between reference types is not permitted in a constant
expression in C++11 onwards.

从commit message中可以看出来,__builtin_addressof()主要是作为std::addressof的”加强版本”,可用于constexpr的场景。

std::addressof

std::addressof是c++11提供的模板函数,用于获取左值表达式的地址。std::addressof的声明如下:

  • template< class T >
    T* addressof(T& arg) noexcept; (since C++11) (until C++17)
  • template< class T >
    constexpr T* addressof(T& arg) noexcept; (since C++17)
  • template < class T>
    const T* addressof(const T&&) = delete; (2) (since C++17)

1) Obtains the actual address of the object or function arg, even in presence of overloaded operator&
2) Rvalue overload is deleted to prevent taking the address of const rvalues.
The expression std::addressof(E) is a constant subexpression, if E is an lvalue constant subexpression.

其中std::addressof的存在是为了应对重载operator&的情况,能够保证获取到正确的地址。而且自从C++17开始,标准规定当std::addressof的参数lvalue constant expression的时候,std::addressof的结果也必须是constant subexpression。std::addressof的可能实现如下:

template< class T >
T* addressof(T& arg) 
{
    return reinterpret_cast<T*>(
               &const_cast<char&>(
                  reinterpret_cast<const volatile char&>(arg)));
}

注意reinterpret_cast<>不允许用于constant expression,且返回值不是constant expression,所以std::addressof的典型实现不能用于 constant expression。

Only the following conversions can be done with reinterpret_cast, except when such conversions would cast away constness or volatility.

对于此有两个问题:

  • reinterpret_cast为什么不能用于constant expression
  • std::addressof的典型实现是怎么操作的?

对于第一个问题,我不是C++ lawyer,暂时无法回答。一些相关资料见:

对于第二个问题,std::addressof的典型实现分为三步,分别是:

  • reinterpret_cast< const volatile char&>(arg)
  • &const_cast< char&>( reinterpret_cast< const volatile char&>(arg)))
  • reinterpret_cast< T*>( &const_cast< char&>(reinterpret_cast< const volatile char&>(arg)))

第一步就是将T&转换成为 const volatile char&。主要原因是std::addressof为了规避对operator&的重载,必须选择一个内置类型进行转换(内置类型没有重载operator&),然后才能安全使用的operator&来获取其地址。这里选择char的原因是,charweakest alignmentreinterpret_cast<>alignment有要求,To-Type的alignment不能比From-Type更stricter(larger),见9.2 reinterpret_cast

The weakest alignment (the smallest alignment requirement) is the alignment of char, signed char, and unsigned char, which equals 1; the largest fundamental alignment of any type is the alignment of std::max_align_t. [Alignment
]

另外由于reinterpret_cast<>不能去掉constness,所以使用const volatile char&来保证转换成功。

第二步就是使用const_cast<>合法地去掉constness。然后此时就可以安全地使用operator&获取地址了。

第三步就是将该地址再转换为原来的类型。

StackOverflow上有一篇相关的问题,见Implementation of addressof

介绍完addressof相关的内容,下面言归正传,由于从c++17开始std::addressof支持constant expression,所以现在libcxx中的std::addressof在c++17开始直接由__builtin_addressof实现,相关patch见Make std::addressof constexpr in C++17 (Clang only).

void&

这篇博客的初衷就是工作当中遇到了在clang编译__builtin_addressof的时候出现的语义分析时的错误,错误与void&相关。__builtin_addressof的函数原型如下,参数类型就是void&。但是在编码过程中是不可能出现void&的,见Why is it impossible to have a reference-to-void?
。而__builtin_addressof能够编译通过的原因是,它有自己的语义分析逻辑,针对__builtin_addressofhasCustomTypechecking为true。

BUILTIN(__builtin_addressof, "v*v&", "nct")

更多内容参见More C++ Idioms/Address Of

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页