我的公司使用消息传递服务器,它将消息获取到 const char*
中,然后将其转换为消息类型。
在询问 this question 后我开始担心这个问题。我不知道消息服务器中有任何不良行为。 const
变量是否可能不会产生别名问题?
例如,假设 foo 是通过以下方式之一在 MessageServer
中定义的:
- 作为参数:
void MessageServer(const char* foo)
- 或者作为
MessageServer
顶部的 const 变量:const char* foo = PopMessage();
现在 MessageServer
是一个巨大的函数,但它从未向 foo
分配任何内容,但是在 MessageServer
逻辑中的 1 点 foo
将转换为选定的消息类型。
auto bar = reinterpret_cast<const MessageJ*>(foo);
bar
只会在随后读取,但将广泛用于对象设置。
这里是否可能存在别名问题,或者 foo
仅被初始化且从未修改的事实拯救了我?
编辑:
Jarod42's answer发现从 const char*
转换为 MessageJ*
没有问题,但我不确定这是否有意义。
我们知道这是非法的:
MessageX* foo = new MessageX;
const auto bar = reinterpret_cast<MessageJ*>(foo);
我们是说这在某种程度上使其合法吗?
MessageX* foo = new MessageX;
const auto temp = reinterpret_cast<char*>(foo);
auto bar = reinterpret_cast<const MessageJ*>(temp);
我对Jarod42's answer的理解是转换为 temp
使其合法。
编辑:
我收到了一些与序列化、对齐、网络传递等相关的评论。这不是这个问题的目的。
这是一个关于 strict aliasing 的问题.
Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to objects of different types will never refer to the same memory location (i.e. alias eachother.)
我要问的是:通过从 char*
进行转换来初始化 const
对象是否会在该对象所在的位置进行优化转换为另一种类型的对象,以便我从未初始化的数据进行转换?
最佳答案
首先,强制转换指针不会导致任何别名冲突(尽管它可能会导致对齐冲突)。
别名是指通过与对象类型不同的泛左值读取或写入对象的过程。
如果对象的类型为 T
,我们通过 X&
读/写它和一个 Y&
那么问题是:
- 可以
X
别名T
? - 可以
Y
别名T
?
是否 X
并不直接重要可以别名 Y
反之亦然,正如您在问题中似乎关注的那样。但是,编译器可以推断是否 X
和Y
完全不兼容,没有这种类型 T
可以由 X
指定别名和Y
,因此可以假设这两个引用引用不同的对象。
所以,要回答你的问题,这一切都取决于 PopMessage
做。如果代码类似于:
const char *PopMessage()
{
static MessageJ foo = .....;
return reinterpret_cast<const char *>(&foo);
}
那么就可以这样写:
const char *ptr = PopMessage();
auto bar = reinterpret_cast<const MessageJ*>(foo);
auto baz = *bar; // OK, accessing a `MessageJ` via glvalue of type `MessageJ`
auto ch = ptr[4]; // OK, accessing a `MessageJ` via glvalue of type `char`
等等。 const
与此无关。事实上,如果您没有使用 const
在这里(或者你把它扔掉)那么你也可以写 bar
和ptr
没问题。
另一方面,如果 PopMessage 类似于:
const char *PopMessage()
{
static char buf[200];
return buf;
}
然后行auto baz = *bar;
会导致 UB 因为 char
不能使用MessageJ
作为别名。请注意,您可以使用 Placement-new 来更改对象的动态类型(在这种情况下, char buf[200]
被认为已停止存在,并且通过 Placement-new 创建的新对象存在,其类型为 T
)。
关于c++ - 使用 const 变量可以避免别名问题吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29121176/