标签: bit-cast

在 C++20 中使用 `std::bit_cast` 创建闭包 (lambda) 对象是否有效?

一位同事向我展示了一个 C++20 程序,其中使用std::bit_cast它捕获的值虚拟创建了一个闭包对象:

#include <bit>
#include <iostream>

class A {
    int v;
public:
    A(int u) : v(u) {}
    auto getter() const { 
        if ( v > 0 ) throw 0;
        return [this](){ return v; }; 
    }
};

int main() {
    A x(42);
    auto xgetter = std::bit_cast<decltype(x.getter())>(&x);
    std::cout << xgetter();
}
Run Code Online (Sandbox Code Playgroud)

由于异常,此处main函数无法调用x.getter()。相反,它调用std::bit_cast将闭包类型作为模板参数,decltype(x.getter())并将&x为新闭包对象捕获的指针作为普通参数xgetter。然后xgetter被调用以获取 object 的值,x否则在main.

该程序被所有编译器接受,没有任何警告和打印42,演示:https : //gcc.godbolt.org/z/a479689Wa

但是程序是否按照标准格式良好,lambda …

c++ lambda language-lawyer c++20 bit-cast

14
推荐指数
1
解决办法
497
查看次数

为什么我不能 std::bit_cast 字符串文字的内容?

在尝试编译时字符串操作时,我遇到了一个奇怪的现象:

#include <bit>

constexpr const char str[4] = "abc";

// error: constexpr variable 'x' must be initialized by a constant expression
constexpr auto x = std::bit_cast<int>("xyz");
// OK
constexpr auto y = std::bit_cast<int>(str);
Run Code Online (Sandbox Code Playgroud)

请参阅编译器资源管理器

为什么允许对char[]存储在全局变量中的 a进行位转换,但不允许对字符串文字进行位转换?std::bit_cast不修改其源并且结果是一个值,因此没有修改字符串文字存储的潜力。

c++ type-punning c++20 bit-cast

7
推荐指数
1
解决办法
108
查看次数

std::bit_cast 填充和未定义的行为

我想知道如何std::bit_cast以明确定义的方式使用,特别是在存在不确定位的情况下。什么时候是std::bit_cast使用定义的行为,什么时候是未定义的行为?

因此,我需要澄清cppreference 关于 std::bit_cast的措辞。我不明白下面这段话的意思:

对于不确定结果的值表示中的每一位,包含该位的最小对象具有不确定值;除非该对象是 unsigned char 或 std::byte 类型,否则行为未定义。结果不包含任何不确定的值。

当输入 ( ) 包含不确定位(明显是填充位)时,所提到的对象是什么以及它们的类型(与其他类型)From的区别是什么?std::byte

让我们写一个例子(不是实际的用例,只是说明具有不确定位的情况):

#include <bit>
#include <cstdint>
struct S40 {
    std::uint8_t a = 0x51;
    std::uint32_t b = 0xa353c0f1;
};
struct S3 {
    std::uint8_t a : 3;
};

int main() {
    S40 s40;
    std::uint64_t a64 = std::bit_cast<std::uint64_t>(s40);
    // (3) on tested compilers, a64 is 0xa353c0f1UUUUUU51 where U is undefined byte
    S3 s3;
    s3.a = 0b101;
    std::uint8_t a8 = std::bit_cast<std::uint8_t>(s3);
    // (4) …
Run Code Online (Sandbox Code Playgroud)

c++ undefined-behavior language-lawyer c++20 bit-cast

6
推荐指数
1
解决办法
243
查看次数

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

C++20 引入了std::bit_cast来处理相同的位,就好像它们是不同的类型一样。所以,基本上它是这样做的:

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;
}
Run Code Online (Sandbox Code Playgroud)

除非没有未定义的行为,允许编译器用硬盘删除方法替换此方法。

我想使用 std::bit_cast,但我坚持使用 C++11。如何正确实现我自己的custom_bit_cast,不使用未定义的行为,而不使用实际的std::bit_cast

后续问题:是否有指针位转换?有一种安全的方法可以让 aT1 *和 aT2 *指向同一位置,并且能够从两者读取和写入,而不会出现未定义的行为?

c++ casting undefined-behavior c++11 bit-cast

4
推荐指数
1
解决办法
2864
查看次数

我可以使用新的放置作为 bit_cast 吗?

我对绕过二进制类型转换限制的方法感兴趣,因为 bit_cast 使用复制到堆栈上的变量,这不是很快。但据我所知,普通类型不会在默认构造函数中初始化内存。这是否意味着,对于将 bit_casting 转换为普通类型,我们可以使用放置 new 和指向我们感兴趣的内存的指针,从而保持内存中的字节不变并避免不必要的复制?在这个问题上是否有我找不到的标准立场,并且禁止我将新的位置与一些“非主题”指针一起使用?

例如,第一个选项是其他人如何使用此功能。第二个选项是我想如何使用它。

#include <iostream>
using namespace std;
class Foo 
{ 
    private: int __unused0 : 31; //A little bit of binary magic
    private: int __unused1 :  1; 
    public: Foo() : __unused0(1), __unused1(1) {} //We're still saving trivially_copyable, so we're good
};

int main()
{
    //char bytes[1024];
    //auto* foo = new(bytes) Foo;
    
    Foo bytes{};
    auto* foo = new(&bytes) int;
    
    cout << *foo;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

UPD:这一切的目的是在不更改容器的情况下处理内存中的原始字节。在最简单的情况下,我需要像“检查寄存器中的高位”这样的小型优化,这是通过单个汇编命令来实现的,例如[x < 0]在处理结构中的位字段时创建一系列命令,例如[x & 0x80][x >> 7][x == …

c++ placement-new c++20 bit-cast

0
推荐指数
1
解决办法
226
查看次数