为什么没有左移位<<对于long int数据类型,移位超过31?

时间:2014-06-09 10:06:00

标签: c++ bit-shift

我想在我的程序中使用以下代码,但是gcc不允许我将我的1转移到31以上。

sizeof(long int)显示8,所以这并不意味着我可以离开直到63?

#include <iostream>

using namespace std;

int main(){
    long int x;
    x=(~0 & ~(1<<63));
    cout<<x<<endl;
    return 0;
}

编译输出以下警告:

left shift `count >= width` of type [enabled by default] `x=(~0 & ~(1<<63))`;
                                                                    ^

,输出为-1。如果我离开了31位,我得到2147483647正如预期的那样。

我希望打开除 MSB 之外的所有位,从而显示数据类型可以容纳的最大值。

5 个答案:

答案 0 :(得分:7)

虽然x类型为long int,但1不是1int1<<63,因此(static_cast<long int>(1) << 63)确实未定义。

按照Wojtek的建议尝试1L << 63或{{1}}。

答案 1 :(得分:3)

您不能使用1(默认情况下为int)将其移出int边界。

除了MSB开启之外,还有一个更简单的方法来获取所有位&#34;对于特定的数据类型

#include <iostream>
#include <limits>

using namespace std;

int main(){
    unsigned long int max = std::numeric_limits<unsigned long int>::max();
    unsigned long int max_without_MSB = max >> 1;
    cout<< max_without_MSB <<endl;
    return 0;
}

注意无符号类型。没有numeric_limits

#include <iostream>
using namespace std;

int main() {

    long int max = -1;
    unsigned long int max_without_MSB = ((unsigned long int)max) >> 1;
    cout << max_without_MSB << endl;

    return 0;
}

答案 2 :(得分:2)

首先让我说一下有关转变的一些事情,这是你问题的根源:

无法保证long int实际上是64位宽。

我能想到的最通用的方法是使用std::numeric_limits

static_cast<long int>(1) << (std::numeric_limits<long int>::digits - 1);

现在你甚至可以制作一个constexpr模板函数:

template <typename Integer>
constexpr Integer foo()
{
    return static_cast<Integer>(1) << (std::numeric_limits<Integer>::digits - 1);
}

因此,使用static_cast<long int>(1) << (std::numeric_limits<long int>::digits - 1)替换班次将解决您的问题,但有更好的方法:

std::numeric_limits包含许多有用的内容,包括:

std::numeric_limits<T>::max(); // the maximum value T can hold
std::numeric_limits<T>::min(); // the minimum value T can hold
std::numeric_limits<T>::digits; // the number of binary digits
std::numeric_limits<T>::is_signed(); // well, do I have to explain? ;-)

有关完整列表,请参阅cppreference.com。您应该更喜欢标准库提供的工具,因为它很可能会有更少的错误,其他开发人员会立即知道它。

答案 3 :(得分:2)

你的头衔有误导性;如果long确实那么大,31可以超越long位。但是,您的代码会移动1,即int

在C ++中,表达式的类型由表达式本身决定。表达式XXXXX具有相同的类型,无论如何;如果您稍后转到double foo = XXXXX;,则并不意味着XXXXX是双倍的 - 这意味着从XXXXXdouble的任何转化都会发生。

如果你想左移一长,那么明确地做,例如1L << 32((long)1) << 32。请注意,long的大小因平台而异,因此如果您不希望代码在其他系统上运行时中断,则必须采取进一步措施,例如使用固定宽度类型,或者转移CHAR_BIT * sizeof(long) - 1

您的预期代码还有另一个问题:如果1L << 63为64位或更低,long会导致未定义的行为。这是因为有符号整数溢出;左移定义与重复乘以2相同,因此尝试“移入符号位”会导致溢出。

要解决此问题,请使用无符号类型,以便可以切换到MSB,例如1ul << 63

从技术上讲,还存在另一个问题:~0如果你没有使用2的补充系统,那就不能做你想做的事情,但是现在忽略这种情况是非常安全的。

使用long x = ~0 & ~(1 << 63)查看您的总体意图。写这个的更简单的方法是:

long x = LONG_MAX;

<climits>定义。如果你想在所有平台上使用64位,那么

int64_t x = INT64_MAX;

NB。如果您不打算使用负值,请分别使用unsigned long xuint64_t

答案 4 :(得分:1)

除非明确提及,否则C中数值的默认数据类型为整数。

在这里你必须输入1作为 long int ,否则它将是一个int。