关于C#转换二进制所引起的一些思考
作者:Jeffcky 发布时间:2021-06-02 18:31:22
前言
最近遇到很有意思转换二进制的问题,有部分童鞋俨然已了解,可能也有一部分童鞋没碰到过也就不知情,这里我们来深入学习下转换二进制所带来的问题。
二进制转换问题
假设现在我们有一个int类型的数据,它的范围区间暂且定在0-15之间,我们需要将其转换为二进制,然后获取二进制中的每一位,若不足4位则0填充。看似很简单是不是,直接通过C#内置APi即可达到此需求,如下:
var binary = Convert.ToString(7, 2).PadLeft(4, '0').ToArray();
上述将数字7转换为包含二进制位的字符串数组形式,7转换二进制然后不足4位以0填充即(0111),我们如下获取二进制位字符串数组为索引的位,结果应该打印出0,对吗?
var zerobit = binary[0];
Console.WriteLine(zerobit);
好像一点毛病也没有,这是在控制台中进行打印,若是将该数据导出到Excel中,你会发现结果将可能是48或49而不是0或1(你可以一试)这是因为如下:
我们通过调试可知实际上在字符0上还携带有48,这个48实际上是字符0的ASCII码,字符1的ASCII码是49,通过如下代码即可证明:
foreach (var b in System.Text.Encoding.UTF8.GetBytes(binary))
{
Console.WriteLine(b.ToString());
}
我们对将对应字符数组索引数据进行如下ToString转换即可避免导出数据时可能出现的问题
var zerobit = binary[0];
Console.WriteLine(zerobit.ToString());
转换字符数组问题
当我们转换为字符数组时,有两种方式,既可采用上述ToArray方法,也可以通过ToCharArray方法来实现,如下,那么哪种方法会更好呢?
var binary = Convert.ToString(7, 2).PadLeft(4, '0').ToArray();
var binary1 = Convert.ToString(7, 2).PadLeft(4, '0').ToCharArray();
此时比较此二者方法的性能好坏,只能去看对应源码实现,首先我们来看看ToCharArray方法,如下:
public unsafe char[] ToCharArray()
{
if (Length == 0)
{
return Array.Empty<char>();
}
char[] array = new char[Length];
fixed (char* smem = &_firstChar)
{
fixed (char* dmem = &array[0])
{
wstrcpy(dmem, smem, Length);
}
}
return array;
}
internal unsafe static void wstrcpy(char* dmem, char* smem, int charCount)
{
Buffer.Memmove((byte*)dmem, (byte*)smem, (uint)(charCount * 2));
}
上述对于ToCharArray代码量还是不多,我们来看看ToArray方法实现,如下:
public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new Buffer<TSource>(source).ToArray();
}
上述只是写了一个扩展方法,我们继续往下看Buffer类的具体实现,如下:
internal Buffer(IEnumerable<TElement> source)
{
TElement[] array = null;
int num = 0;
ICollection<TElement> collection = source as ICollection<TElement>;
if (collection != null)
{
num = collection.Count;
if (num > 0)
{
array = new TElement[num];
collection.CopyTo(array, 0);
}
}
else
{
foreach (TElement item in source)
{
if (array == null)
{
array = new TElement[4];
}
else if (array.Length == num)
{
TElement[] array2 = new TElement[checked(num * 2)];
Array.Copy(array, 0, array2, 0, num);
array = array2;
}
array[num] = item;
num++;
}
}
items = array;
count = num;
}
从代码量上看就觉得ToArray方法实现稍微复杂一点,所以我们选择使用ToCharArray会更好,我要是如此草草结束此文,一定会喷。原归正传,我们一步步来分析,如上做了一点优化,首先会判断参数是否属于集合接口,若是则直接通过复制转换为数组形式,但是我们知道字符串肯定没有实现ICollection<T>接口,所以走另外一个条件分支,但是有的童鞋可能就有疑问了,此时为何可以遍历呢?那是因为针对字符实现了IEnumerable<char>接口,所以可以进行遍历,如下:
public sealed class CharEnumerator : IEnumerator, ICloneable, IEnumerator<char>, IDisposable
{......}
接下来则是初始化容量为4的数组,为何这里为4呢?这里我认为应该谈不上优化,与其说是实现者的一种拍脑袋的想法,我倾向于理解为是一种权衡或考量,既然转到此分支说明一定是转换为二进制位的数组,比如上述进行填充后长度刚好为4。再接下来无用我再多讲,就是遍历所有字符数组,将每一个字符串添加到数组中去,直到数组长度和变量值(num)相等最终进行一次性复制,最终将数组赋值给数组元素以及将变量num赋值给数组元素的数量(count)。
来源:https://www.cnblogs.com/CreateMyself/p/13216212.html


猜你喜欢
- 本文实例讲述了Android自定义ViewPager的方法。分享给大家供大家参考,具体如下:package com.rong.activit
- 1.现象描述原来项目在Android studio 2.3一切正常,升级3.0之后报如下错误:Error:Cannot choose bet
- 前言在产品发布前夕,经常因为编写各类设计文档感到心碎,倒不是难,而是比较繁琐,举例来说,像编写数据库文档这种操作来说,对于新手,甚至很多有一
- 在很多场景中我们需要验证时间日期的是否属于正确的格式,验证时间是否符合常规的。1、验证 yyyy-MM-dd HH:mm:dd 格式的日期S
- 本文实例为大家分享了javaweb文件打包批量下载,供大家参考,具体内容如下// 批量下载未批改作业 @RequestMapping(val
- 以下是介绍利用List的subList方法实现对List分页,废话不多说了,直接看代码把/** *//** * List分页 &
- CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承至FrameLayout,给它设置layout
- 在java中,单例有很多种写法,面试时,手写代码环节,除了写算法题,有时候也会让手写单例模式,这里记录一下单例的几种写法和优缺点。1.初级写
- 双色球选号规则红球是1~33选6个,蓝球1~16选1个。它有17721088种排列组合,这个代码实现了如何将一组双色球号码 转换成第n个排列
- Android实现分享长图并且添加全图水印前言:长图一般是ScrollView和ListView。 我们需要取得这两个控件的完整显示的图片。
- 手机二维码扫码登录已经成为了现代互联网时代的一种普遍的登录方式。它的出现,极大地方便了用户登录的流程,减少了用户输入用户名和密码的麻烦。在二
- SwipeRefresh基于原生的SwipeRefreshLayout 做了封装处理此项目中包括种:1.原生SwipeRefreshLayo
- 查了下网上的一些资料,感觉比较复杂,这里,我这几使用两种很简单的办法解决了中文乱码问题。Spring版本:3.2.2.RELEASEJack
- Android中oncreate中获得控件高度或宽度的实现方法onCreate函数只是提供了数据初始化的机会,此时还没有正式绘制图形。在图形
- 一、TabHost用法通常情况下我们会通过继承TabActivity,调用getTabHost()获取TabHost实例,下面是具体过程。T
- 前言由于业务需要,后端需要返回一个树型结构给前端,包含父子节点的数据已经在数据库中存储好,现在需要做的是如何以树型结构的形式返给给前端。数据
- 本文实例为大家分享了C#线程中弹窗的制作代码,供大家参考,具体内容如下首先建立一个ShowFrom窗体,窗体中放入两个按钮分别为确定和取消分
- 因为案例比较简单,所以简单用AndroidApplication -> Game -> Stage 搭建框架 一、主入口,无特殊
- Spring数据源的配置数据源(连接池)的作用数据源(连接池)是提高程序性能如出现的事先实例化数据源,初始化部分连接资源使用连接资源时从数据
- 因为最近重新看了泛型,又看了些反射,导致我对Object、T(以下代指泛型)、?产生了疑惑。我们先来试着理解一下Object类,学习Java