表示范围所需的位的编译时计算
Compile-time calculation of bits needed to represent a range
我需要在编译时计算表示范围所需的位数。对于从 0 到 n 的无符号范围,它很简单:
constexpr unsigned bits_to_represent(uintmax_t n)
{
return n > 0
? 1 + bits_to_represent(n/2)
: 0;
}
对于有符号范围,我有:
constexpr unsigned bits_in_range(intmax_t min,intmax_t max)
{
return bits_to_represent(max >= 0
? static_cast<uintmax_t>(max) - min
: max - min);
}
但是,这会导致 MSVC 2015 (最近更新) 抱怨:
警告 C4308:负整数常数转换为无符号类型
你能解释一下为什么会这样吗?作为一种解决方法,我static_cast分钟即可uintmax_t,但我不喜欢这个解决方案,因为它似乎不如我的首选解决方案便携,甚至可能是未定义的行为,即使我怀疑这是否可能发生在编译时。
我不确定 MSVC 给出警告的确切原因,但您正在做的可能导致不良行为的一件事是在算术运算和比较中混合有符号和无符号整数。
您可以阅读此内容以获取由此引起的问题的示例:http://blog.regehr.org/archives/268
我会尝试像这样重写你的函数:
constexpr unsigned bits_in_range(intmax_t min,intmax_t max)
{
return bits_to_represent(
static_cast<uintmax_t>(max) - static_cast<uintmax_t>(min));
}
这种方式对程序员更友好。当您对不匹配的整数类型进行算术运算时,编译器将不得不执行隐式转换以使它们匹配。这样,它就不必这样做了。即使 max 和 min 为负数,如果您确定 max >= min
,这仍然会给出定义明确且正确的结果。
分 4 部分进行。 每个最小值至少为零。
如果它们共享相同的符号(0 为正),则 2s 补码整数的差值可以表示为它们自己类型的一部分。
这就剩下max<min
和max
积极和min
负面的案例。
如果我们假设uint_max_t
足够大,那么算术和转换为该类型的行为都根据数学模2^n
.
因此unsigned(a)-unsigned(b)
实际上是从 b 到 a 作为有符号整数的无符号距离。
C = A-B mod X
C = A-B + kX
B+C=A+kX
C
正且小于X
,X
大于B-A
,给我们C
一定是三角洲。
感谢您的评论,即使他们没有解释Microsoft警告。Clang 编译干净,因此可能是编译器中的错误。由于C++中从有符号值到无符号值的转换性质,只需强制转换两个值即可获得正确答案(再次假设最小值<= max):
constexpr unsigned bits_in_range(intmax_t min,intmax_t max)
{
return bits_to_represent(static_cast<largest_uint>(max) -
static_cast<largest_uint>(min));
}
代码的有效性可以从标准草案的这一部分推断出来(我看了最新的草案,但确信这里没有变化)。
4.7 积分转换
如果目标类型为无符号,则结果值是与源全等的最小>无符号整数 整数(模 2n,其中 n 是用于表示 无符号类型)。
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- C++ 在编译时具有函数计算全局变量
- 如何在常量计算表达式中获取编译时错误?
- 如何判断是否在编译时计算了"constexpr"(无需手动检查)
- 在编译时何时计算范围::视图?
- C++编译器能在编译时计算出文字的除法结果吗
- 在编译时计算"if"子句
- 根据计算机上安装的库依赖项编译不同的代码
- 强制在编译时计算类的类的常量成员
- 在 64 位 Linux armv8 计算机上编译 32 位二进制文件时遇到问题
- 在编译时计算基类的偏移量
- C++ constexpr:在编译时计算标准数组
- 如何判断表达式是在编译时还是运行时计算的?
- 计算对数组编译时中对元素的差异
- 我正在尝试计算 char 数组中的内容,直到 null 终止,但每次编译时,我都会得到一个比我的数组大的数字
- Clang 在编译时不会计算非 constexpr 变量的 constexpr 函数的值
- C++:当与 std::cout 一起使用时,constexpr 函数在编译时不会计算
- 如何避免由于编译时计算的值而导致"unreachable statement"?
- C++ 计算编译时常量,同时防止整数常量溢出
- 从捕获 constexpr 函数返回值的变量中删除 constexpr 会删除编译时计算