C++严格的混叠不可知强制转换

C++ strict-aliasing agnostic cast

本文关键字:不可知 转换 C++      更新时间:2023-10-16

我在Stack Overflow中读过很多关于严格混叠的QA,但它们都很常见,讨论总是涉及C++标准的深层细节,这些细节几乎总是很难正确理解。尤其是当标准不直接说东西,而是以一种模糊不清楚的方式描述某事时。所以,我的问题可能与这里的质量保证重复,但是,请回答一个特定的问题:

这是进行"nonalias_cast"的正确方法吗?:

template<class OUT, class IN>
inline auto nonalias_cast(IN *data) {
char *tmp = reinterpret_cast<char *>(data);
return reinterpret_cast<OUT>(tmp);
}
float f = 3.14;
unsigned *u = nonalias_cast<unsigned *>(&f);
*u = 0x3f800000;
// now f should be equal 1.0

我想答案是否定的。但有什么好的变通办法吗?当然,除了禁用严格混叠标志。联合也不是一个方便的选择,除非有一种方法可以在nonalias_cast函数体内安装联合破解。memcpy在这里也不是一个选项——数据更改应该同步。

一个不可能的梦想还是一个难以捉摸的现实?

UPD:

好吧,既然我们对"这可能吗?"这个问题的回答是否定的,我想再问你一个困扰我的问题:

将如何解决此任务?我的意思是,有很多实际任务更不需要"玩点小游戏"的方法。例如,假设您必须编写这样的IEEE-754浮点转换器。我更关心问题的实际方面:如何找到一个变通方法来实现目标?以一种起码的"@#$的痛苦"的方式。

正如其他答案正确指出的那样:这是不可能的,因为您不允许通过unsigned指针访问float对象,并且没有可以删除该规则的强制转换。

那么你是如何解决这个问题的呢?不要通过unsigned指针访问对象!使用float*char*来传递对象,因为它们是严格混叠下唯一允许的指针类型。然后,当您实际需要访问unsigned语义下的对象时,您可以执行从float*到本地unsignedmemcpy(完成后再返回memcpy)。您的编译器将足够聪明,可以为此生成高效的代码。

请注意,这意味着您的接口上到处都是float*,而不是unsigned*。这正是这项工作的原因:类型系统在任何时候都知道正确的数据类型。只有当你试图将float作为unsigned*通过类型系统时,事情才会开始崩溃,你希望首先会同意这是一个可疑的想法。

这是执行"nonalias_cast"的正确方法吗?

否。

但是有什么好的解决方法吗?

再次,没有

原因很简单,&f不是某个类型为unsigned int的对象的地址,指针上再多的强制转换也不会改变这一点。

否,您的nonalias_cast不工作,也无法工作。

类型别名规则不是(直接)关于转换指针的。事实上,您的转换都没有未定义的行为。这些规则是关于通过另一种类型的指针访问某个类型的对象。

无论如何转换指针,指向的对象仍然是float对象,通过unsigned指针访问它会违反类型别名规则。


一个不可能的梦想还是一个难以捉摸的现实?

在标准C++中,这是不可能的。