C++ 使用reinterpret_cast的符号别名
以下面的代码为例C++ 使用reinterpret_cast的符号别名,c++,language-lawyer,memcpy,signed,reinterpret-cast,C++,Language Lawyer,Memcpy,Signed,Reinterpret Cast,以下面的代码为例 #include <iostream> void func() { int i = 2147483640; while (i < i + 1) { std::cerr << i << '\n'; ++i; } return; } int main() { func(); } 我已经在-O3上用Clang 8和GCC 9使用-Wall-Wextra-
#include <iostream>
void func() {
int i = 2147483640;
while (i < i + 1)
{
std::cerr << i << '\n';
++i;
}
return;
}
int main() {
func();
}
我已经在-O3
上用Clang 8和GCC 9使用-Wall-Wextra-Wpedantic-O3-fsanizize=address、未定义的
参数尝试了上述代码,没有得到错误或警告,循环在包装到INT\u MIN
后终止
告诉我
类型别名
每当试图通过AliasedType类型的glvalue读取或修改DynamicType类型的对象的存储值时,除非满足以下条件之一,否则该行为未定义:
- AliasedType是DynamicType的有符号或无符号变体(可能是cv限定的)
从我的理解来看,这意味着对于类型别名,不考虑符号性,并且使用
重新解释\u cast
的代码具有定义良好的语义(尽管无论如何有点俗气)。这里的别名是完全合法的。见:
如果程序试图通过访问对象的存储值
一个glvalue,其类型与下列类型之一不相似([conv.qual])
以下类型的行为未定义:53
(11.1)对象的动态类型
(11.2)有符号或无符号类型的类型
对应于对象的动态类型
我认为,还值得讨论实际的溢出问题,它不一定需要重新解释cast。隐式积分转换也可以达到同样的效果
unsigned x = i;
++x;
i = x; // this would serve you just fine.
这段代码将是C++20之前实现定义的,因为您将从无法由目标类型表示的值进行转换
由于C++20,这段代码将是格式良好的
看
另一方面,如果您想要整数溢出语义,您最好从unsigned type开始。您的代码完全合法,cpp reference是一个非常好的源代码。您可以在标准中找到相同的信息 如果程序试图通过类型与以下类型之一不相似([conv.qual])的glvalue访问对象的存储值,则行为未定义:
- 对象的动态类型
- 与对象[…]的动态类型相对应的有符号或无符号类型
我想知道如果没有
通过无符号x=a重新解释cast
的话,人们是否也不能这样做++x;返回x代码>。那会不会有同样的效果呢,但是在c++20之前就已经有效了吗?这并没有回答关于别名的问题,尽管它确实有效it@JonasMüller你的问题是关于递增还是别名的?@formerlyknownas_463035818如果a
是INT\u MAX
,那么x
将不适合a
使其成为实现定义的行为。我同意,这里还有第二个隐含的问题(涉及溢出部分),但主要的问题是reinterpret\u cast
的使用在这里是否有效?当然,这与库比在cppreference@LightnessRacesinOrbit(“变体”)上选择的措辞不同。CPP引用比普通英语更容易,目标当然比标准更容易阅读。@好奇人,哦,你是在引用一个旧版本的C++标准。此规则来自C。在C中,此规则是定义成员访问权限所必需的。在C++中,它被删除了,因为它不是必需的,成员访问是在标准中的其他地方定义的。参见核心语言问题@curiousguy值的解释取决于表达式类型,对于其他对象,其中找到的值的解释取决于用于访问它们的表达式类型([expr.component])。@curiousguy 6个月前,我实际上也在问自己同样的问题。这条规则的要点是什么:。在评论和讨论之后,有人解释说这只是一个C语言,C++委员会内部就这一点进行了讨论。显然,他们决定删除此规则。@LightnessRacesinOrbit:[basic.lval]/11此访问的有效性。缺少的是通过引用未签名/已签名对象的已签名/未签名版本来修改未签名/已签名对象的行为。但是我没有看到禁止它的语句。@SergeyA:然后指向规范中的一行,该行说明了当您通过对无符号对象的引用写入有符号对象时实际发生的情况。因为我可以指向规范中的行,这些行说明了当您(例如)通过基类指针/引用调用派生类的成员函数时会发生什么。但对于已签名/未签名,不存在类似的语句。转化是合法的;访问是合法的,但是发生的事情并没有在规范中说明。这类事情总是不符合我的喜好。这是该标准中为数不多的几个领域之一,这些领域似乎假设接近于该标准中的金属位逻辑places@SergeyA:“它可能是未指定的吗?”是的,这是规范中的一个缺陷。在C++20中,随着这两个变量的补充更改,它可以以完全定义良好的方式得到解决。只有在某个地方有措辞才能做到这一点。@NicolBolas:在编写该标准时,作者希望某些实现能够并且能够有效地支持某些操作,但并非对所有实现都有意义,即使标准没有强制要求,也将继续在有意义的实现上得到支持。如果标准中存在缺陷,那不是没有规定行为,而是没有表明它从未打算详尽无遗。
unsigned x = i;
++x;
i = x; // this would serve you just fine.