c++ - 使用 const 变量可以避免别名问题吗

标签 c++ constants alias reinterpret-cast strict-aliasing

我的公司使用消息传递服务器,它将消息获取到 const char* 中,然后将其转换为消息类型。

在询问 this question 后我开始担心这个问题。我不知道消息服务器中有任何不良行为。 const 变量是否可能不会产生别名问题?

例如,假设 foo 是通过以下方式之一在 MessageServer 中定义的:

  1. 作为参数:void MessageServer(const char* foo)
  2. 或者作为 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反之亦然,正如您在问题中似乎关注的那样。但是,编译器可以推断是否 XY完全不兼容,没有这种类型 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在这里(或者你把它扔掉)那么你也可以写 barptr没问题。

另一方面,如果 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/

相关文章:

c++ - VirtualAllocEx 成功返回一个基地址,但是 WriteProcess 失败,错误是 487

c++ - 将 Botan 加密结果输出到 QDomDocument,反之亦然

c++ - 在 const 对象上调用非常量函数

C:数学常数的枚举 VS #define?

sql-server-2008 - SQL Server "."别名不工作

bash - 在 find -exec 中使用别名

shell - 别名 "rm -rf/"="echo ' 白痴'"为什么不工作?

c++ - OpenCV VideoWriters 的输出目录有问题

c++ - 使用 Boost.Units 和 Boost.Multiprecision

java 8 : difference between class. getName() 和字符串文字