c++ - 为什么赋值表达式中的重叠必须是精确的并且对象必须具有相同的类型,这是什么意思?
问题描述
浏览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*
,然后将单独的字节推送到流中(这需要取消引用,类似于上面的示例)?
解决方案
在某些平台上,考虑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
实例,如果它们识别重叠的实例,则可能会发生故障。p2
struct s
推荐阅读
- javascript - 服务器端渲染元素应在初始渲染时滚动到底部
- javascript - 如何使用 XMLHttpRequest 仅使用 Javascript 在数组中插入多个 JSON
- rust - 为什么传递给 map() 的闭包不带引用,而传递给 filter() 的闭包带引用?
- typescript - 在 Typescript 界面中强制执行类型
- r - 没有名为“fansi”的包
- swift - 在不使用 NumberFormatter 的情况下将 Double 转换为具有最小小数位数的字符串
- node.js - 图片上传到 cloudinary 两次
- nestjs - 如何在 Nestjs 中创建种子?
- amazon-web-services - AWS CodeBuild 可以同时构建两个 Docker 映像吗?
- sharepoint - 使用 ag-grid 导出 excel/csv 在 SPFx 中不起作用