简体   繁体   English

C++11 中 std::bit_cast 的安全等效项

[英]Safe equivalent of std::bit_cast in C++11

C++20 introduced std::bit_cast for treating the same bits as if they were a different type. C++20 引入了std::bit_cast来处理相同的位,就好像它们是不同的类型一样。 So, basically it does this:所以,基本上它是这样做的:

template <typename T1, typename T2>
T2 undefined_bit_cast(T1 v1) {
    T1 *p1 = &v1;
    T2 *p2 = (T2 *)p1; // Uh oh.
    T2 v2 = *p2; // Oh no! Don't do that!
    return v2;
}

except without the undefined behavior that allows a compiler to replace this method with a hard drive deletion method.除了没有允许编译器用硬盘删除方法替换此方法的未定义行为。

I would like to use std::bit_cast, but I'm stuck using C++11.我想使用 std::bit_cast,但我无法使用 C++11。 How do I correctly implement my own custom_bit_cast , using no undefined behavior, without using the actual std::bit_cast ?如何正确实现我自己的custom_bit_cast ,不使用未定义的行为,而不使用实际的std::bit_cast

Followup question: is there a pointer bit cast?后续问题:是否有指针位转换? A safe way to have a T1 * and a T2 * pointing at the same location, and be able to read and write from both, without it being undefined behavior?T1 *T2 *指向同一位置并能够从两者读取和写入的安全方法,而不是未定义的行为?

template <class T2, class T1>
T2 cpp11_bit_cast(T1 t1) {
  static_assert(sizeof(T1)==sizeof(T2), "Types must match sizes");
  static_assert(std::is_pod<T1>::value, "Requires POD input");
  static_assert(std::is_pod<T2>::value, "Requires POD output");

  T2 t2;
  std::memcpy( std::addressof(t2), std::addressof(t1), sizeof(T1) );
  return t2;
}

you can probably relax the pod restriction to trivially copyable.您可能可以将 pod 限制放宽到可轻松复制。

Compilers are pretty good with the above being optimized to good assembly.编译器非常好,上面的内容被优化为良好的汇编。

As for the pointer bit, there is no safe way to read an object of type T1 as if it was an object of type T2 where T1 and T2 are arbitrary.至于指针位,没有安全的方法来读取T1类型的 object,就好像它是T2类型的 object,其中T1T2是任意的。 There are cases where it is allowed, but they are quite narrow.有些情况是允许的,但范围很窄。

Almost every C or C++ compiler, likely including every compiler that would be suitable for tasks that would involve bit_cast, includes configuration options to extend the languages by defining behaviors upon which the Standard imposes no requirements.几乎每个 C 或 C++ 编译器(可能包括适用于涉及 bit_cast 的任务的每个编译器)都包括配置选项,通过定义标准未强加要求的行为来扩展语言。 I haven't seen the any published Rationale documents for the C++ Standard, but the authors of the C Standard explicitly describe UB as, among other things, identifying areas of "conforming language extension", and regard support for such "popular extensions" as a quality-of-implementation issue outside the Standard's jurisdiction.我还没有看到任何已发布的 C++ 标准的基本原理文档,但 C 标准的作者明确将 UB 描述为识别“符合语言扩展”的区域,并将对此类“流行扩展”的支持视为标准管辖范围之外的实施质量问题。

The fact that a construct would not be portable among all C or C++ compiler configurations does not imply that it cannot or should not be safely used on configurations that support it.一个构造不能在所有 C 或 C++ 编译器配置中移植的事实并不意味着它不能或不应该安全地用于支持它的配置。 I'd suggest designing some headers that can define macros to handle things one of three ways, depending upon implementation:我建议设计一些可以定义宏的标头来处理三种方式之一,具体取决于实现:

  1. For implementations that support bit_cast, use that.对于支持 bit_cast 的实现,请使用它。

  2. For implementations that extend the language with compiler-specific syntax to allow support for type punning, use that.对于使用特定于编译器的语法来扩展语言以支持类型双关语的实现,请使用它。

  3. For other implementations, specify that compilers must be configured to extend the language with support for type punning at least when using common sequences of operations.对于其他实现,指定编译器必须配置为扩展语言以支持类型双关,至少在使用常见的操作序列时。

While there may exist implementations for which none of those approaches would be suitable, on most implementations at least one of them would be effective.虽然可能存在这些方法都不适合的实现,但在大多数实现中,至少其中一种是有效的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM