通过负面警告摆脱 gcc shift

Posted

技术标签:

【中文标题】通过负面警告摆脱 gcc shift【英文标题】:Getting rid of gcc shift by negative warning 【发布时间】:2008-11-06 00:15:14 【问题描述】:

我有一些看起来像这样的代码:

template<unsigned int A, unsigned int B>
int foo() 
  int v = 1;
  const int x = A - B;
  if (x > 0) 
    v = v << x;
  
  bar(v);

gcc 会抱怨 x 对于 A、B 的某些实例是负数;但是,我确实进行了检查以确保它是非负数。解决这个问题的最佳方法是什么?我知道我可以将x 转换为unsigned int,但这会导致警告x 大于v 的宽度(因为它会将负数转换为正数)。我知道有一种解决方法涉及创建一个新的模板化 shift 函数,但如果可能的话,我想避免这种情况。

【问题讨论】:

【参考方案1】:

由于 A 和 B 在编译时已知,因此您不仅可以摆脱警告,还可以摆脱运行时 if,无需任何强制转换,如下所示:

#include <iostream>
using namespace std;

template< unsigned int A, unsigned int B >
struct my

    template< bool P >
    static void shift_if( int & );

    template<>
    static void shift_if< false >( int & ) 

    template<>
    static void shift_if< true >( int & v )  v <<= A - B; 

    static void op( int & v )  shift_if< (A > B) >( v ); 
;

template< unsigned int A, unsigned int B >
int foo()

    int v = 1;
    my< A, B >::op( v );
    return v;


int main() 
    cout << foo< 1, 3 >() << endl;
    cout << foo< 3, 1 >() << endl;
    cout << foo< 300, 1 >() << endl;
    cout << foo< 25, 31 >() << endl;
    return 0;

【讨论】:

一个非常好的解决方案。尽管它需要调整以解决 (A - B >= 32) 问题。顺便说一句,if 无论如何都可能被排除,因为编译器可以检测到它永远不会发生。 @Evan Teran,谢谢!我注意到 shift-wrap 问题,但 OP 的原始代码让它换行,所以我认为这就是他想要的。我怀疑您对编译器优化的看法是正确的,但在我的版本中,表达式 A - B 是无符号的,因此避免了警告。 理想情况下,如果该数字为正数,我希望代码在我移动过多时警告我,如果为负数,则根本不警告我(因为它不会被执行) .我想没有办法绕过它,但这种方式。很高兴知道。 您可以通过声明而不是定义额外的特化来使过度的正偏移成为错误。【参考方案2】:

为什么不将 x 设为 unsigned char 类型并强制转换呢?您确定不需要移动超过 255 位吗?

const unsigned char x = static_cast<unsigned char>(A - B);

或者也许使用掩码来确保移位在这样的范围内:

const unsigned int x = static_cast<unsigned int>(A - B) & 0x1f; // limit A-B to have a range of (0 - 31)

编辑:

作为对评论的回应,这里有一个想法:

template<unsigned int A, unsigned int B>
int foo() 
  int v = 1;
  const int x = A - B;
  if (x > 0) 
    v = v << (static_cast<unsigned int>(x) & 0x1f);
  
  bar(v);

注意:您可以将 0x1f 替换为:(CHAR_BIT * sizeof(T) - 1)

编辑:响应最新评论,此代码不会发出任何警告编译:g++ -W -Wall -ansi -pedantic test.cc -o test

#include <iostream>

template<unsigned int A, unsigned int B>
int foo() 
  int v = 1;
  const int x = A - B;
  if (x > 0) 
    v = v << (static_cast<unsigned int>(x) & 0x1f);
  
  return v;


int main() 
    std::cout << foo<1, 3>() << std::endl;
    std::cout << foo<3, 1>() << std::endl;
    std::cout << foo<300, 1>() << std::endl;
    std::cout << foo<25, 31>() << std::endl;

【讨论】:

我相信如果右侧是负数,它会将其转换为unsigned int,这将使其成为正数。如果A-B 的结果是否定的,我不想运行代码。 因为它知道编译时的值,所以任何大于 32 的数字都会标记另一个警告,即移位大于类型宽度的数字。因此,虽然这确实解决了负面问题,但它会引发第二个警告。 我将值限制为0-32,所以应该没有警告 啊,对不起,我错过了那个面具。我以为它掩盖了负号。【参考方案3】:

这行得通吗?

const short unsigned int x = A - B;

它切断的位比需要切断的多得多,但如果你的 A - B 值足够小......

【讨论】:

更具体地说:我有A == 25B == 31。这给了我x == -6 看起来像111...11010 并且截断它仍然会给我一个相当大的数字

以上是关于通过负面警告摆脱 gcc shift的主要内容,如果未能解决你的问题,请参考以下文章

Windows 64x下的GCC中的printf和%llx

GCC 不尊重“pragma GCC diagnostic”以消除警告 [重复]

gcc 多行注释警告

如何摆脱 PHP 中的 filesize() 警告?

警告为错误 - 如何摆脱这些

符号可见性和 gcc 警告