C++严格的混叠不可知强制转换
C++ strict-aliasing agnostic cast
我在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*
到本地unsigned
的memcpy
(完成后再返回memcpy
)。您的编译器将足够聪明,可以为此生成高效的代码。
请注意,这意味着您的接口上到处都是float*
,而不是unsigned*
。这正是这项工作的原因:类型系统在任何时候都知道正确的数据类型。只有当你试图将float
作为unsigned*
通过类型系统时,事情才会开始崩溃,你希望首先会同意这是一个可疑的想法。
这是执行"nonalias_cast"的正确方法吗?
否。
但是有什么好的解决方法吗?
再次,没有
原因很简单,&f
不是某个类型为unsigned int
的对象的地址,指针上再多的强制转换也不会改变这一点。
否,您的nonalias_cast
不工作,也无法工作。
类型别名规则不是(直接)关于转换指针的。事实上,您的转换都没有未定义的行为。这些规则是关于通过另一种类型的指针访问某个类型的对象。
无论如何转换指针,指向的对象仍然是float
对象,通过unsigned
指针访问它会违反类型别名规则。
一个不可能的梦想还是一个难以捉摸的现实?
在标准C++中,这是不可能的。
- 检查不带转换的扫描格式
- 如何在不强制转换每个参数的情况下删除初始值设定项列表中从 int 到 char 的缩小转换?
- 为什么此指针值不能转换为整数的规则是什么?
- 使用 .data() 将字符数组转换为 std::string 不会转换整个数组
- 类型不可知的抽象以使用相同的运行时接口处理正向和反向迭代器和范围?
- 将字符串存储为十六进制而不进行转换
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)
- 尝试在不使用转换概念的情况下呈现此代码
- 静态强制转换允许转换对象指针,但不允许转换整数
- 返回类型不可知模板类成员功能
- 在C++中实现双链表的最佳操作系统不可知方法
- 将 32 位浮点数和不强制转换的 32 位整数与双精度进行比较,当其中一个值可能太大而无法完全适合另一种类型时
- Windows VC++编译器允许一种奇怪的c样式转换方式(或者它可能不是转换??)
- 为什么 ostream 不能转换为 ostream?
- 不允许转换为无法访问的基类
- 为什么static_cast不使用转换运算符来指针指向const
- C++严格的混叠不可知强制转换
- 为什么 nullptr 不能转换为 int?
- 为什么 boost::interprocess::managed_shared_ptr 到 non-const 不能转换
- 为什么C++设置迭代器不能转换为布尔值?