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

Why doesn't left bit shift << shift beyond 31 for long int datatype?

本文关键字:lt int 为什么 long 数据类型      更新时间:2023-10-16

我想在我的程序中使用以下代码,但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之外的所有位都被打开,从而显示数据类型可以容纳的最大值。

虽然您的xlong int类型,但1不是。1int,所以1<<63确实没有定义。

试试(static_cast<long int>(1) << 63),或者Wojtek建议的1L << 63

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

对于特定的数据类型,有一种更简单的方法可以使"除MSB之外的所有位都打开"

#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;
}

注意unsigned类型。无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;
}

你的标题是误导;如果long确实有那么大,那么long可以超越31位。但是你的代码改变了1,这是一个int

在c++中,表达式的类型由表达式本身决定。表达式XXXXX无论如何都具有相同的类型;如果你后来转到double foo = XXXXX;,这并不意味着XXXXX是双精度,它意味着从XXXXX转换到double

如果你想左移一个长字符,那么显式地进行,例如1L << 32((long)1) << 32。请注意,long的大小在不同的平台上是不同的,所以如果你不想让你的代码在不同的系统上运行时中断,那么你必须采取进一步的措施,比如使用固定宽度的类型,或者通过CHAR_BIT * sizeof(long) - 1来移动。

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

要解决这个问题,使用unsigned类型,它可以很好地转移到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

首先让我说明一些关于你的问题根源的变化:

不能保证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)替换shift会解决你的问题,但是有一个更好的方法:

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获取完整列表。您应该更喜欢标准库提供的功能,因为它很可能会有更少的错误,并且其他开发人员立即知道它。

除非明确说明,否则C中数值的默认数据类型是整型。

这里必须将1强制转换为long int,否则它将是int型。