在什么情况下,reinterpret_cast对char* (或char[N])是未定义的行为,以及何时定义了行为?我应该用什么经验法则来回答这个问题?
正如我们从this question中学到的,以下是未定义的行为:
alignas(int) char data[sizeof(int)];
int *myInt = new (data) int; // OK
*myInt = 34; // OK
int i = *reinterpret_cast<int*>(data); // <== UB! have to use std::launder但是,在什么时候,我们可以对一个reinterpret_cast数组执行一个char,并且它不是一个未定义的行为?以下是几个简单的例子:
new,只有reinterpret_cast:
(Int) char datasizeof(int);*reinterpret_cast(data) = 42;//第一个强制写入UB?int I=*reinterpret_cast(数据);//读取如何?*reinterpret_cast(数据)= 4;//第二次写入如何?int j=*reinterpret_cast(数据);//或二读?
int的生存期什么时候开始?这是与data的声明吗?如果是,data的生存期什么时候结束?data是一个指针呢?
data_ptr =新字符(Int);*reinterpret_cast(data_ptr) = 4;//这是UB吗?int I= *reinterpret_cast(data_ptr);//读取如何?这些案件中有UB吗?都是吗?这个问题的答案在C++11和C++1z之间有变化吗?
发布于 2016-09-11 01:59:01
这里有两个规则:
这些规则是区分“内存位置”或“存储区域”和“对象”的重要部分。
您的所有代码示例都会遇到相同的问题:它们不是您将它们投射到的对象:
对齐(Int)焦炭数据;
它创建类型为char[sizeof(int)]的对象。该对象不是int。因此,您可能不会像访问它一样访问它。不管是读还是写,你还是激怒了UB。
同样:
char* data_ptr =新字符(Int);
它还创建了一个类型为char[sizeof(int)]的对象。
char buffer100;
这将创建一个类型为char[100]的对象。该对象既不是MsgType1也不是MsgTypeF。因此,您不能访问它,就好像它是。
请注意,这里的UB是作为Msg*类型之一访问缓冲区的时候,而不是在检查第一个字节时。如果您的所有Msg*类型都是微不足道的可复制的,那么完全可以接受读取第一个字节,然后将缓冲区复制到适当类型的对象中。
switch (buffer[0]) {
case '1':
{
MsgType1 msg;
memcpy(&msg, buffer, sizeof(MsgType1));
handle(msg);
}
break;
case 'F':
{
MsgTypeF msg;
memcpy(&msg, buffer, sizeof(MsgTypeF));
handle(msg);
}
break;
// ...
}请注意,我们讨论的是语言状态将是什么未定义的行为。编译器可以很好地处理其中的任何一个。
这个问题的答案在C++11和C++1z之间有变化吗?
自从C++11 (特别是basic.life)以来,已经有了一些重要的规则澄清。但规则背后的意图并没有改变。
https://stackoverflow.com/questions/39429476
复制相似问题