错误从bool *转换为void *到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个字节的类型系统。通过使用另一个也会调用UB的指针类型访问类型,您也违反了strict aliasing rule。此外,如果bool数组不是properly aligned,您将获得UB。在x86上,这不会造成任何问题,因为默认情况下,x86允许未对齐的访问,但是在大多数其他体系结构上您会遇到段错误。

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


更新

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

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

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

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

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

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

我不明白您对char*的看法。您是说从任何类型强制转换为char*都是有效的吗?

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

您可以使用char*来代替系统的单词来别名。规则允许char*(包括signed charunsigned char)的例外。始终假定char*为其他类型的别名。

它用于诸如memcpy之类的事情,其中​​您将代表一种类型的字节复制到另一个目的地

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

从技术上mempcy收到void*,到char*的演员仅用于演示

另请参见