通过负面警告摆脱 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 == 25
和B == 31
。这给了我x == -6
看起来像111...11010
并且截断它仍然会给我一个相当大的数字以上是关于通过负面警告摆脱 gcc shift的主要内容,如果未能解决你的问题,请参考以下文章