-1

通常在 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。显然,这里不是这种情况。

4

1 回答 1

4

static_cast<int*>(ptr)[0]强制转换ptrint*读取第一个元素。由于原始数组只有 2 个字节,因此您正在读取它之外的内容(因为您正在读取 4-byte int)并调用未定义的行为,除非int您的系统上是 2-byte 类型。您还违反了严格的别名规则,因为您使用不同的指针类型访问了一个类型,该类型也调用了 UB。此外,如果 bool 数组未正确对齐,您将获得 UB 。在 x86 上它不会导致任何问题,因为 x86 默认情况下允许未对齐访问,但在大多数其他架构上您会遇到段错误

static_cast<int>(test[0])OTOH 将test[0](即 a boolint转换为完全有效的值转换。


更新:

类型int*指对象为 4 字节长的指针,而bool*指对象为 2 字节长的指针

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

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

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

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

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

我不明白你在说什么char*。您是说从任何类型转换char*为有效?

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

您可以使用char*别名而不是系统的单词。规则允许char*(包括signed charunsigned char)例外。它总是假定char*别名其他类型。

它用于memcpy将表示类型的字节复制到不同目的地的地方

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

技术上mempcy接收void*,演员char*表只是用来演示的

也可以看看

于 2020-10-11T13:21:18.387 回答