【发布时间】:2016-04-28 20:55:08
【问题描述】:
让我们考虑将无符号短值(或任何其他无符号整数类型)的右 N 位清零的函数(它的可能实现之一)。可能的实现如下所示:
template<unsigned int shift>
unsigned short zero_right(unsigned short arg) {
using type = unsigned short;
constexpr type mask = ~(type(0));
constexpr type right_zeros = mask << shift; // <-- error here
return arg & right_zeros;
}
int check() {
return zero_right<4>(16);
}
使用此代码,我可以访问的所有编译器都以一种或另一种方式抱怨可能的溢出。 CLang 是最明确的,有以下明确的信息:
错误:从 'int' 到 'const type' 的隐式转换(又名 'const unsigned short') 将值从 1048560 更改为 65520 [-Werror,-Wconstant-conversion]
这段代码在我看来定义明确且清晰,但是当 3 个编译器抱怨时,我变得非常紧张。我在这里错过了什么吗?真的有可能发生可疑的事情吗?
附:虽然 zeriong out left X bits 的替代实现可能会受到欢迎和有趣,但这个问题的主要焦点是发布的代码的有效性。
【问题讨论】:
-
@TavianBarnes,对于无符号参数,它们不能提升为有符号整数。
-
不是您要问的,但您可能需要注意(并且不要提防)的是,如果您将无符号整数左移 'n' 位,其中 'n' 是>= 你转换的类型的位数,那就是未定义的行为。
-
@SergeyA 但这仍然是问题所在:
<<的结果是 int,而不是短。在赋值之前将mask << shift的结果转换回type会使错误消失。 -
@JesperJuhl,我已经解决了这个问题,只是不想让问题变得过于复杂。
-
@SergeyA cppreference 还说“返回类型是左操作数的类型在积分提升之后。”(强调我的)
标签: c++ language-lawyer bit-shift integer-overflow