我不是高级C ++程序员。但是我已经使用C ++很长一段时间了。所以,我喜欢玩它。最近我在考虑以编程方式最大化变量的方法。所以我尝试使用按位运算符来填充 1 的变量。然后是signed
和unsigned
问题。我对记忆表现的了解并不是很好。但是,我最后编写了以下代码,该代码适用于signed
和unsigned
short
,int
和long
(尽管int
和long
基本相同)。不幸的是,对于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;
}
答案 0 :(得分:4)
您的代码的基本问题在于语句
val &= 0 << i;
和
val |= 1 << i;
如果val
长于int
。
在第一个表达式中,0 << i
(很可能)始终为0,无论i
(从技术上讲,它都会遇到下面描述的相同的未定义行为,但您不会遇到问题。 )所以根本不需要循环;所有语句都做同样的事情,即将val
归零。当然,val = 0;
可能是一种更简单的写作方式。
问题1 << i
是常量文字1
是int
(因为它足够小,可以表示为int
,int
是用于整数常数的最窄表示。由于1
是int
,1 << i
也是i
。如果int
大于或等于int
中的值位数,则该表达式具有未定义的行为,因此理论上结果可能是任何结果。但实际上,结果可能与1
的宽度相同,因此只会影响低阶位。
当然可以将T
转换为T
类型(尽管一般情况下,您可能需要对1
签名时的角落情况保持谨慎),但它更容易通过使用T
,cstdint
中定义的最大宽度无符号整数类型,将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 :(得分: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>