从 bool* 到 void* 到 int* 的错误转换

Bug casting from bool* to void* to int*

通常在 C++ 中,一个参数 void* user_data 可以用来传递任意类型。

我用它来传递布尔数组。但是,我有一个错误,我从 bool* --> void* --> int* 投射,我得到了奇怪的结果。这是一个例子。

#include <iostream>

int main() {
    bool test[2] = { };
    void *ptr = static_cast<void*>(test);
    std::cout << static_cast<bool*>(ptr)[0] << '\n';
    std::cout << static_cast<int*>(ptr)[0] << '\n';
    std::cout << static_cast<int>(test[0]) << '\n';
}

输出:

$ g++ int_bool.cpp 
$ ./a.out 
0
-620756992
0

有人可以向我解释一下问题出在哪里吗?通常当我从 bool 转换为 int 时,没有问题:false 映射到 0,true 映射到 1。显然,这里不是这种情况。

static_cast<int*>(ptr)[0]ptr 转换为 int* 并读取第一个元素。因为原始数组只有 2 个字节,所以你在它外面读取(因为你正在读取一个 4 字节的 int)并调用未定义的行为,除非 int 是你的 2 字节类型系统。您还违反了 strict aliasing rule by accessing a type using a different pointer type which also invokes UB. Besides you'll get UB if the bool array isn't properly aligned。在 x86 上它不会引起任何问题,因为 x86 默认允许未对齐的访问,但在大多数其他架构上你会遇到段错误

static_cast<int>(test[0]) OTOH 将 test[0](这是一个 bool)转换为 int,并且是完全有效的值转换。


更新:

The type int* refers to a pointer whose object is 4-bytes long, whereas bool* refers to a pointer whose object is 2-bytes long

没有。取消引用变量 var 时,将从该地址开始的内存中读取长度为 sizeof(var) 的内存量,并将其视为该变量的值。所以*bool_ptr将从内存中读取1个字节而*int_ptr将从内存中读取4个字节(如果boolint分别是1字节和4字节类型)

在您的例子中,bool 数组包含 2 个字节,因此当从 static_cast<int*>(ptr) 读取 4 个字节时,2 个字节 inside 数组和 2 个字节 之外读取数组。如果您声明 bool test[4] = {}; (或更多元素),您会看到 int* 取消引用成功完成,因为它读取了属于您的所有 4 个 bool,但您仍然遇到未对齐问题

现在尝试将布尔值更改为 非零 并查看

bool test[4] = { true, false, true, false };

你很快就会意识到,将指针转换为不同的指针类型并不是像简单的值转换(即转换)那样简单地读取旧类型并转换为新类型,而是不同的“内存”治疗”。这本质上只是一个 reinterpret_cast,您可以阅读它以了解有关此问题的更多信息

I don't understand what you are saying about char*. You're saying casting from any type to char* is valid?

从任何其他 指针 类型转换为 char* 是有效的。阅读上面关于严格别名规则的问题:

You can use char* for aliasing instead of your system's word. The rules allow an exception for char* (including signed char and unsigned char). It's always assumed that char* aliases other types.

它用于诸如 memcpy 之类的事情,您可以在其中将代表一种类型的字节复制到不同的目的地

bool test[4] = { true, true, true, true };
int v;
memcpy((char*)&test, (char*)&v, sizeof v);

技术上 mempcy 接收 void*,转换为 char* 仅用于演示

另见