通过负面警告消除gcc偏移

Getting rid of gcc shift by negative warning

本文关键字:gcc 偏移 警告      更新时间:2023-10-16

我有一些代码看起来像:

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函数,但如果可能的话,我希望避免这种情况。

由于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;
}

为什么不将x设为无符号字符类型并进行强制转换?你肯定不需要移位超过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;
}

这样行吗?

const short unsigned int x = A - B;

它所截取的比特比需要截取的要多得多,但如果你的a-B值足够小。。。