请看以下代码
#include <iostream>
void func() {
int i = 2147483640;
while (i < i + 1)
{
std::cerr << i << '\n';
++i;
}
return;
}
int main() {
func();
}
这段代码显然是错误的,因为 while 循环只有在带符号 int i
溢出时才能终止,这是未定义行为(UB),因此编译器可能会将其优化为无限循环(Clang 在 -O3
上确实会这样做),或者执行其他奇怪的操作。我现在的问题是:根据我对 C++ 标准的理解,等效于带符号性的类型可能会别名(即指针 int*
和 unsigned*
可能会别名)。为了进行一些奇怪的带符号“包装”,下面的代码是否具有未定义行为?
#include <iostream>
static int safe_inc(int a)
{
++reinterpret_cast<unsigned&>(a);
return a;
}
void func() {
int i = 2147483640;
while (i < safe_inc(i))
{
std::cerr << i << '\n';
++i;
}
return;
}
int main() {
func();
}
我已经使用Clang 8和GCC 9在-O3
和-Wall -Wextra -Wpedantic -O3 -fsanitize=address,undefined
参数下尝试了上述代码,没有出现任何错误或警告,并且循环在回绕到INT_MIN
后终止。
cppreference.com告诉我:
类型别名
每当尝试通过AliasedType类型的glvalue读取或修改DynamicType类型对象的存储值时,除非以下条件之一成立,否则行为未定义:
- AliasedType是DynamicType的(可能带有cv限定符的)有符号或无符号变体。
据我所知,这意味着就类型别名而言,符号性不被考虑,使用 reinterpret_cast
的代码具有良好定义的语义(虽然仍然有点作弊)。