首页 > 解决方案 > 为什么赋值表达式中的重叠必须是精确的并且对象必须具有相同的类型,这是什么意思?

问题描述

浏览Enumeration of Core Undefined Behavior时,我偶然发现了[expr.ass] 案例。给出一个例子:

int x = 1;
char* c = reinterpret_cast<char*>(&x);
x = *c;

这段代码到底有什么问题?是不是因为它访问x操作数的两侧,但其中之一是通过别名指针?这会解决:

int x = 1;
char* c = reinterpret_cast<char*>(&x);
int y = *c;
x = y;

那么够了吗?如果不是,那么通过访问对象的任何部分实际上是非法的char*假设对象的sizeof大于char's,为了保持“部分”部分)?如果是,那么二进制序列化是如何工作的,因为它依赖于使用 (可能是 cv-qualified) 给给定对象起别名char*,然后将单独的字节推送到流中(这需要取消引用,类似于上面的示例)?

标签: c++language-lawyerundefined-behavior

解决方案


在某些平台上,考虑long *x,*y,*z;到最有效的处理方式*x = *y + *z;可能是:

  • 将 的低位字与*y的低位字*z相加,注意进位,并将结果存入 的低位字*x

  • 将 的高位字*y*z上一步的任何进位相加,并将其存储到 的高位字中*x

如果 的低位字*x与 的高位字重合,则按该顺序*y执行操作将导致高位字*y在被用于表达式之前被覆盖。

请注意,对于 clang 和 gcc,重叠的限制不仅限于原始类型。类似的构造会出现一个相关的问题:

struct s { int x[2]; };

int test(struct s *p1, struct s *p2)
{
  if (*(p1->x))
    *(p2->x+1) = 1;
  return *p1->x;
}

在这里,所有实际的加载和存储都是通过取消引用 type 的指针来完成的int*,而不是 type struct s*,gcc 生成的代码要求识别相同的实例或不相交的p1实例,如果它们识别重叠的实例,则可能会发生故障。p2struct s


推荐阅读