【问题标题】:disable spurious "warning: left shift count >= width of type"禁用虚假“警告:左移计数> =类型宽度”
【发布时间】:2015-02-02 15:37:32
【问题描述】:

在使用 gcc 编译某些模板代码时,我收到了一个虚假的“警告:左移计数 >= 类型宽度”:

template <int N> class bitval {
unsigned long  val;
#pragma GCC diagnostic ignored "-Wall"
    const bitval &check() {
        if (N < sizeof(unsigned long) * CHAR_BIT && val >= (1UL << N)) {
            std::clog << val << " out of range for " << N << " bits in " << std::endl;
            val &= (1UL << N) - 1; }
        return *this; }
#pragma GCC diagnostic pop
};

问题是当它用 N == 64 实例化时,它会给出警告。

现在警告完全是虚假的,因为代码检查 N 是否足够大以至于不需要检查/掩码,因此当 N 为 64 时,将永远不会发生移位。但是 gcc 还是会发出警告。所以我正在尝试禁用警告,但我无法弄清楚关闭它所需的#pragma 魔法......

【问题讨论】:

  • 显然这不是虚假的,编译器比你更了解实例化。 G++ 很好,让您知道代码中有未定义的行为。如果N 大于63,我建议使用enable_if 禁用此模板
  • 所以您只是假设unsigned long 是64 位类型?好的。
  • 不,我不认为 OP 假设(参见 sizeof(unsigned long) * CHAR_BIT 但我猜编译器没有意识到这意味着 (1UL &lt;&lt; N) 后面的 if 是“安全”。
  • @Mgetz:但没有未定义的行为。仅当第一次检查 N 成功时才评估班次,在这种情况下,班次在范围内且定义明确 - 如问题所述。
  • @Mgetz:不,正如问题所说,这只是一个虚假的警告。可能对代码的分析不够深入,无法确定无法触发未定义的行为。

标签: c++ gcc


【解决方案1】:

标签调度救援:

const bitval& check() {
  constexpr bool enough_bits = (N < sizeof(unsigned long) * CHAR_BIT);
  using enough_bits_t = std::integral_constant<bool, enough_bits>;
  return check( enough_bits_t{} );
}
const bitval& check(std::false_type /*enough bits*/) {
  return *this;
} 
const bitval& check(std::true_type /*enough bits*/) {
  if (val >= (1UL << N)) {
    std::clog << val << " out of range for " << N << " bits in \n";
    val &= (1UL << N) - 1;
  }
  return *this;
}

决定(是否有足够的位数)是一个编译时常数,所以我将它计算为一个。

然后,我根据该决定构建一个类型(std::true_typestd::false_type),并分派给两个不同的重载之一。

因此,N 太大而无法移动那么远的代码永远不会被实例化,因此不会发出警告。如果决策中存在逻辑错误,并且代码被实例化,我会收到编译器警告而不是静默(如果您设法禁用警告,并且出现逻辑错误,您将获得静默 UB)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-22
    • 2020-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多