二进制、八进制和十六进制 32 位结构体
简化了基数 2、8 和 16 位数据的用法。
引言
虽然数据在内存或磁盘中显然以二进制形式存储,但 .NET 会在我们希望查看数据或设置值时自动将其转换为十进制(基数 10)。它确实提供了一些用于获取或设置其他基数的值的功能,如下所示。
内置函数
设置 Int32(基数 = 2 表示二进制,8 表示八进制,16 表示十六进制):Convert.ToInt32 (string, base)
。例如:
string binaryString = "11111111";
int i = Convert.ToInt32 (binaryString, 2);
i
现在等于 255。
十六进制的替代方法
int i = 0xFF;
i
现在等于 255。从 Int32 获取值:Convert.ToString (integer, base)
。例如:
int i = 255;
string binaryString = Convert.ToString (i, 2);
binaryString
现在等于 1111111。
此类库
这些在大多数情况下都足够了,但我经常发现我需要一种更自然/更灵活的方式来包装这些函数。此类库是一些简单的代码来解决这个问题。所有结构体都围绕一个 Int32
(m_Value
) 构建,因此分别称为 Bin32
、Oct32
和 Hex32
。
在每个结构体中,您首先会注意到几个 implicit
和一个 explicit
运算符方法。
在 Bin32
中,第一个是
public static implicit operator Bin32(int value) {... }
这段魔法允许我们直接接受一个 int
来创建 Bin32
的实例,而无需在我们的代码中调用重载构造函数(它会自动调用私有构造函数)。例如,您可以这样做:
Bin32 binaryValue = 255;
而不是通常的
Bin32 binaryValue = new Bin32(255);
下一个类似,但允许我们使用字符串
public static implicit operator Bin32(string value) {... }
因此,我们可以简单地使用
Bin32 binaryValue = "11111111";
再往下是一个与第一个类似的方法,但 Bin32
和 int
的顺序颠倒了。
public static implicit operator int(Bin32 value) {... }
这使得我们可以自动将我们的值用作 int
,而无需显式转换。
Bin32 binaryValue = "11111111";
int i = binaryValue;
下一行与前一行不同,因为它是一个 explicit
而不是 implicit
public static explicit operator string(Bin32 value) {... }
通过使用 explicit
关键字,这意味着我们必须显式转换为此类型才能使用该方法。
Bin32 binaryValue = "11111111";
string binaryString = (string)binaryValue;
为什么不在这里使用 implicit
?嗯,拥有多个隐式返回类型可能会导致一些严重的头疼。只需尝试将 explicit
改为 implicit
,然后尝试
Console.WriteLine(binaryValue);
糟糕!这会产生很多歧义,因为它不知道要写入控制台的内容 - **选择太多了!**
最初,我将 string
设置为 implicit
,将 int
设置为 explicit
。这样可以正常工作,但需要更多的代码,因为所有一元、二元、逻辑和条件运算符都需要重载。将 int
保持为 implicit
,我们可以使用 Microsoft 已经为 Int32
运算符完成的代码 :-)。
有关运算符重载的更多信息,请参阅我的文章:C# 运算符重载入门。
除了显式转换外,还有两个 ToString
方法(一个用于 Oct32
)。
我实现了标准的 IComparable
和 IEquatable
接口。Parse
、ToString
和 TryParse
方法主要包含在本文开头介绍的内置函数中。
这里还有一个类 - 一个名为 ExtensionMethods
的静态类,其中声明了一些简单的扩展方法,为 int
和 string
提供了额外的功能,而无需我们实际调用任何 Bin32
、Oct32
或 Hex32
实例。
使用中
将 BinOctHex.dll 的引用添加到您的项目中。使用这些结构体非常简单。附带了一个简单的示例。您对 int
可以做的所有常规操作都可以对这些结构体中的任何一个进行(包括位移,这在十六进制和二进制中更有意义)。您还可以对这些结构体的组合执行操作。例如:
(bin number % hexnumber) / octnumber;
使用动机
我经常需要对多个二进制和十六进制数字进行计算,并将结果以任一基数显示(八进制较少,但我为完整性包含了它)。
想象一下像这样的简单计算:
((1 + 2 + 3 + 4 + 5) % 4) * 15 = ?
如果它们都是 int
,那很容易,但如果它们是混合的二进制和十六进制字符串呢?
((00000001 + 00000010 + 00000011 + 00000100 + 00000101) % 00000100) * 0F = ?(base 8)
目前,您必须手动将每个字符串转换为 int
,然后再次转换以显示正确基数下的答案。使用这个,您可以像看到的那样执行计算。
string a1 = "00000001";
string b1 = "00000010";
string c1 = "00000011";
string d1 = "00000100";
string e1 = "00000101";
string f1 = "00000100";
string g1 = "0F";
// Using methods built in.
int h1 = (
(Convert.ToInt32(a1, 2) +
Convert.ToInt32(b1, 2) +
Convert.ToInt32(c1, 2) +
Convert.ToInt32(d1, 2) +
Convert.ToInt32(e1, 2))
% Convert.ToInt32(f1, 2))
* Convert.ToInt32(g1, 16);
Console.WriteLine(Convert.ToString(h1, 8));
Bin32 a2 = a1;
Bin32 b2 = b1;
Bin32 c2 = c1;
Bin32 d2 = d1;
Bin32 e2 = e1;
Bin32 f2 = f1;
Hex32 g2 = g1;
// Using Bin32, Oct32, Hex32 structs - a simple one liner
Oct32 h2 = ((a2 + b2 + c2 + d2 + e2) % f2) * g2;
Console.WriteLine((String)h2);
我还对上面的代码进行了计时,两者都以大致相同的时间执行 - 有时第一部分稍快一些,有时第二部分 - 所以它根本不会减慢速度。直接使用 int
的速度大约是快 50 倍,但如果您的数据是其他基数,那么您总是需要进行转换。如果您想将其更改为 int
来消除开销 - 这就是隐式转换的用途。
历史
- 2008 年 8 月 7 日:初始版本。
- 2008 年 10 月 6 日:链接到C# 运算符重载入门。