问题描述
通常在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个字节(如果bool
和int
分别是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 char
和unsigned char
)的例外。始终假定char*
为其他类型的别名。
它用于诸如memcpy
之类的事情,其中您将代表一种类型的字节复制到另一个目的地
bool test[4] = { true,true };
int v;
memcpy((char*)&test,(char*)&v,sizeof v);
从技术上mempcy
收到void*
,到char*
的演员仅用于演示
另请参见