c++ - 类型和未定义行为之间的指针转换

标签 c++ casting undefined-behavior

在 C++ 中,如果 AB 是不同的类,将 A* 转换为 通常是未定义的行为B* 然后解引用,即给定

A *a = ...;

写是未定义的行为

((B*)a)->x

即使碰巧 x 在两个类中具有相同的类型和偏移量。

另一方面,char* 对转换规则有特殊的豁免。这么写是不是定义明确了?

((B*)(char*)a)->x

最佳答案

这道题取决于AB的类型。

如果BA的基类,或者AB的基类,那么((B *)a) 是静态转换,所以如果 B((B *)a)->x 是正确的基类;或者如果 B 是派生类并且 a 实际上指向类型为 B 的对象的 A 部分。

如果AB 是不相关的类型,那么我们必须查看严格的别名规则。下面是一些具体的代码:

struct A { int p,q,r; } a;
struct B { int z,y; } b;
static_assert( sizeof a == 3 * sizeof(int) );
static_assert( sizeof b == 2 * sizeof(int) );

假设断言通过,我们知道 ((B *)&a)->y 必须指定与 a.q 相同的内存位置。

这里有两种思想流派:

  1. ((B *)&a)->yint 类型的左值,a.qa.q 的对象输入 intintint 兼容,因此不存在别名冲突。

  2. Evaluating ((B *)&a)->y 表示 (*(B *)&a).y,它首先计算 * (B *)&a,这违反了严格的别名规则,因为 *(B *)&a 没有指定包含 B 的内存位置。

我个人喜欢 (1);我不认为情况 2 中的评估算作“访问”,严格的别名规则谈论“访问”:

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

但是这里有一个灰色区域,因为虽然读取 ((B *)&a)->y 访问的是 int 对象的存储值;目前尚不清楚它是否也被视为访问包含该对象的结构的存储值的一部分。


((B*)(char*)a)->x 对后一种情况没有影响,我们仍然以 int 类型的左值结束。在继承的情况下,如果它是多重继承,那么这可能会破坏代码,因为它将 static_cast 变成了 reinterpret_cast

关于c++ - 类型和未定义行为之间的指针转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32108642/

相关文章:

C++ lambda 表达式作为函数模板中的参数

c++ - C++ 中与 Matlab 中的 wpd 和 newpnn 函数类似的函数?

c++ - XERCESC 2.7 内存泄漏问题

java - 为什么在将 Throwable 向下转换为 Exception 时没有给出未经检查的转换警告?

c++ - 将函数指针reinterpret_cast与void(*)()比较是否为未定义行为?

c++ - 如何重启套接字程序?

c++ - 当它被称为 shared_ptr<Basic> 时调用派生类方法

c# - 将 IList 转换为列表

c++ - 在两个相似类之间使用 reinterpret_cast 时出现错误?

c++ - 括号是否强制评估顺序并定义未定义的表达式?