构造带符号的位域
constructing signed bit-fields
下面我构建了一些我正在处理的使用位域的代码的小示例。
在实现比较运算符时,我注意到它没有按预期工作。问题是 -1 似乎不小于 1.
想了一会儿,我觉得构造函数中的掩码有问题。
我在那里添加了 "aValue & MAX_VALUE",否则编译器会发出转换警告。但是,首先使用 MAX_VALUE 进行掩码,然后转换为 int32_t 并没有给我正确的结果。
有谁知道我该如何解决这个问题?
当我在 main() 方法中编写 minusOne.v = -1;
时,我似乎确实得到了预期的结果。但我不确定如何在构造函数中编写它(没有收到转换警告)。
#include <iostream>
#include <cstdint>
using namespace std;
struct int27_t
{
int32_t v:27;
constexpr static int32_t MIN_VALUE = -(1L << 26);
constexpr static int32_t MAX_VALUE = (1L << 26) - 1;
constexpr static int32_t MASK = 0x7FFFFFF;
int27_t() : v(0) {}
explicit int27_t(int32_t aValue) : v(static_cast<int32_t>(aValue & MAX_VALUE)) {}
friend bool operator<(const int27_t& aLhs, const int27_t& aRhs);
};
bool operator<(const int27_t& aLhs, const int27_t& aRhs)
{
return aLhs.v < aRhs.v;
}
int main()
{
int27_t minusOne{-1};
int27_t plusOne{1};
cout << "MAX_VALUE == " << int27_t::MAX_VALUE << " == 0x" << hex << int27_t::MAX_VALUE << dec << endl;
cout << "-1 == " << minusOne.v << " == 0x" << hex << minusOne.v << dec << endl;
cout << "-1 cast to int32_t: " << static_cast<int32_t>(minusOne.v) << " == 0x" << hex << static_cast<int32_t>(minusOne.v) << dec << endl;
cout << "-1 < 1 ? " << (minusOne < plusOne) << endl;
cout << endl;
}
程序输出
MAX_VALUE == 67108863 == 0x3ffffff
-1 == 67108863 == 0x3ffffff
-1 cast to int32_t: 67108863 == 0x3ffffff
-1 < 1 ? 0
布尔运算不适用于有符号类型。
您只是 &
-ing 掉构造函数中的符号。
你的代码基本上有四个问题:
- 不要对有符号类型使用二进制算法。只是不要这样做。如果真的有必要,arithmetically 转换为
unsigned
(乘以 -1 并注意溢出),做一些事情并返回签名 arithmetically.
- 您依赖于带符号数字的某种表示形式。据我所知(在符号类型方面是 C99),该语言提供了三种不同的:符号和大小、一个补码和补码,cf. ISO/IEC 9899:TC2 §6.2.6.2-2.
- 假设 two's complement,这应该适用于几乎所有最近的平台,你的
MIN_VALUE
相差一个。
- 请不要使用 bit-fields。几乎所有最近的架构都会将其扩展为某种 word-sized 类型。你可能除了麻烦什么也得不到,因为有符号溢出是未定义的行为。所以用这种方式限制有符号类型的范围是没有意义的。
下面我构建了一些我正在处理的使用位域的代码的小示例。 在实现比较运算符时,我注意到它没有按预期工作。问题是 -1 似乎不小于 1.
想了一会儿,我觉得构造函数中的掩码有问题。
我在那里添加了 "aValue & MAX_VALUE",否则编译器会发出转换警告。但是,首先使用 MAX_VALUE 进行掩码,然后转换为 int32_t 并没有给我正确的结果。
有谁知道我该如何解决这个问题?
当我在 main() 方法中编写 minusOne.v = -1;
时,我似乎确实得到了预期的结果。但我不确定如何在构造函数中编写它(没有收到转换警告)。
#include <iostream>
#include <cstdint>
using namespace std;
struct int27_t
{
int32_t v:27;
constexpr static int32_t MIN_VALUE = -(1L << 26);
constexpr static int32_t MAX_VALUE = (1L << 26) - 1;
constexpr static int32_t MASK = 0x7FFFFFF;
int27_t() : v(0) {}
explicit int27_t(int32_t aValue) : v(static_cast<int32_t>(aValue & MAX_VALUE)) {}
friend bool operator<(const int27_t& aLhs, const int27_t& aRhs);
};
bool operator<(const int27_t& aLhs, const int27_t& aRhs)
{
return aLhs.v < aRhs.v;
}
int main()
{
int27_t minusOne{-1};
int27_t plusOne{1};
cout << "MAX_VALUE == " << int27_t::MAX_VALUE << " == 0x" << hex << int27_t::MAX_VALUE << dec << endl;
cout << "-1 == " << minusOne.v << " == 0x" << hex << minusOne.v << dec << endl;
cout << "-1 cast to int32_t: " << static_cast<int32_t>(minusOne.v) << " == 0x" << hex << static_cast<int32_t>(minusOne.v) << dec << endl;
cout << "-1 < 1 ? " << (minusOne < plusOne) << endl;
cout << endl;
}
程序输出
MAX_VALUE == 67108863 == 0x3ffffff
-1 == 67108863 == 0x3ffffff
-1 cast to int32_t: 67108863 == 0x3ffffff
-1 < 1 ? 0
布尔运算不适用于有符号类型。
您只是 &
-ing 掉构造函数中的符号。
你的代码基本上有四个问题:
- 不要对有符号类型使用二进制算法。只是不要这样做。如果真的有必要,arithmetically 转换为
unsigned
(乘以 -1 并注意溢出),做一些事情并返回签名 arithmetically. - 您依赖于带符号数字的某种表示形式。据我所知(在符号类型方面是 C99),该语言提供了三种不同的:符号和大小、一个补码和补码,cf. ISO/IEC 9899:TC2 §6.2.6.2-2.
- 假设 two's complement,这应该适用于几乎所有最近的平台,你的
MIN_VALUE
相差一个。 - 请不要使用 bit-fields。几乎所有最近的架构都会将其扩展为某种 word-sized 类型。你可能除了麻烦什么也得不到,因为有符号溢出是未定义的行为。所以用这种方式限制有符号类型的范围是没有意义的。