记忆中有多长时间?

时间:2017-10-08 17:10:52

标签: c++ c++11 bitwise-operators

我不是高级C ++程序员。但是我已经使用C ++很长一段时间了。所以,我喜欢玩它。最近我在考虑以编程方式最大化变量的方法。所以我尝试使用按位运算符来填充 1 的变量。然后是signedunsigned问题。我对记忆表现的了解并不是很好。但是,我最后编写了以下代码,该代码适用于signedunsigned shortintlong(尽管intlong基本相同)。不幸的是,对于long long,该计划失败了。

那么,long long幕后发生了什么?它在记忆中如何表现?此外,有没有更好的方法在C ++中实现相同的目标?

#include <bits/stdc++.h>
using namespace std;



template<typename T>
void Maximize(T &val, bool isSigned)
{
    int length = sizeof(T) * 8;
    cout << "\nlength = " << length << "\n";

    // clearing
    for(int i=0; i<length; i++)
    {
        val &= 0 << i;
    }

    if(isSigned)
    {
        length--;
    }

    val = 1 << 0;
    for(int i=1; i<length; i++)
    {
        val |= 1 << i;

        cout << "\ni = " << i << "\nval = " << val << "\n";
    }
}


int main()
{
    long long i;

    Maximize(i, true);

    cout << "\n\nsizeof(i) = " << sizeof(i) << " bytes" << "\n";
    cout << "i = " << i << "\n";

    return 0;
}

3 个答案:

答案 0 :(得分:4)

您的代码的基本问题在于语句

val &= 0 << i;

val |= 1 << i;

如果val长于int

在第一个表达式中,0 << i(很可能)始终为0,无论i(从技术上讲,它都会遇到下面描述的相同的未定义行为,但您不会遇到问题。 )所以根本不需要循环;所有语句都做同样的事情,即将val归零。当然,val = 0;可能是一种更简单的写作方式。

问题1 << i是常量文字1int(因为它足够小,可以表示为intint是用于整数常数的最窄表示。由于1int1 << i也是i。如果int大于或等于int中的值位数,则该表达式具有未定义的行为,因此理论上结果可能是任何结果。但实际上,结果可能与1的宽度相同,因此只会影响低阶位。

当然可以将T转换为T类型(尽管一般情况下,您可能需要对1签名时的角落情况保持谨慎),但它更容易通过使用Tcstdint中定义的最大宽度无符号整数类型,将uintmax_t转换为至少与val |= std::uintmax_t(1) << i; 一样宽的无符号类型:

long long

在实际代码中,通常会看到最宽整数类型为val |= 1ULL << i; 的假设:

#include <limits>

如果程序从不尝试使用扩展整数类型实例化模板,它将正常工作。

当然,这不是找到整数类型的最大值的方法。正确的解决方案是8*sizeof(T),然后使用std::numeric_limits<T>::max()

的相应专业化

C ++只允许一个表示正(和无符号)整数,三个可能表示负符号整数。正整数和无符号整数简单地表示为二进制表示法中的位序列。也可能有填充位,并且有符号整数具有单个符号位,在正整数的情况下必须为0,因此无法保证表示中有k个有用位,即使数字也是如此已知字节中的位数为8(理论上,它可能更大)。 [注1]

负有符号整数的符号位始终为1,但值位有三种不同的格式。最常见的是&#34;二进制补码&#34;,其中被解释为正数的值位正好比数字的实际值高2 k ,其中{ {1}}是值位的数量。 (这相当于为符号位指定2 -k 的权重,这就是为什么它被称为2s补码。)

另一种选择是&#34;补码&#34;,其中值位全部被反转。这与两个补码表示完全不同。

第三个允许的替代方案是&#34; sign-magnitude&#34;,其中值位正好是负数的绝对值。此表示通常用于浮点值,但很少用于整数值。

符号幅度和一个补码都有一个缺点,即有一个位模式代表&#34;负0&#34;。另一方面,二元补码表示具有以下特征:最负的可表示值的大小比最大正可表示值的大小大一,结果是-x和{{ 1}}可能溢出,导致未定义的行为。

注释

  1. 我认为理论上可以在值位和符号位之间插入填充,但我当然不知道该功能的任何实际实现。然而,尝试将1移入符号位位置的事实是未定义的行为使得假设符号位与值位连续是不正确的。

答案 1 :(得分:3)

  

我正在考虑以编程方式最大化变量的方法。

你正试图重新发明轮子。 C ++ STL已经具有此功能:std::numeric_limits::max()

// x any kind of numeric type: any integer or any floating point value
x = std::numeric_limits<decltype(x)>::max();

这也更好,因为你不会转发未定义的行为。

答案 2 :(得分:2)

正如 harold 所评论的那样,解决方案是使用T(1) << i代替1 << i。同样如一些程序员家伙所提到的,long long表示为连续字节(通常为8个字节),如果它是signed,则在MSB处具有符号位。 / p>