• .Net冷知识之UInt32转换为Byte的方法1、2、3


    老天爷你算是赢了,忽冷忽热的搞毛啊。最近因为各种原因掌握了丰富的就诊经验(好吧,和这篇博文一样毫无意义的技能Get★daze)。

    本来这篇博文的内容是上周冲澡的时候脑洞大开的成果,结果由于各(lan)种(de)原(dong)因(shou)拖延到了今天,那就顺手当作三八妇女节献礼好了(<ゝω・)綺羅星☆。

    今天要讨论的是有多少种无趣的手段把一个UInt32拆成4个Byte。至于其他长度整形的拆解就请自行举一反三吧。

    首先,肯定是第一个想到的,就是进行位运算。没什么好说的,关门放代码:

    byte p1=(byte)(ipt >> 24);
    byte p2=(byte)(ipt >> 16);
    byte p3=(byte)(ipt >> 8);
    byte p4=(byte)(ipt);

    上述代码通过位移分别从高到低取得4个byte,简单实用。通常这种方法就完全够用了(唯一的问题就是需要口算位移……好烦)。但是标题都剧透了1、2、3,这时候放弃博文就结束了。那么,乘我还没被冻死就进入方法2吧。

    方法2的想法倒是很直接:既然一个UInt32在内存中分配了4个字节的长度,为何我们不直接访问这4个字节呢?就像吐司面包一样,直接平分4片就是了。

    为了平分一个UInt32,就要直接操作内存。C#中除了几个特殊的地方,平常没有人需要用到指针这玩意。不过既然玩的就是脑洞打开,还是果断祭出许久没见到的指针吧:

    byte* p = (byte*)&ipt;
    byte p1=p[3];
    byte p2=p[2];
    byte p3=p[1];
    byte p4=p[0];

    由于X86平台上采用的是Little Ending布局,所以这里内存访问的顺序是和直觉相反的(好吧,其实内存布局问题早忘了,要不是看到结果反了也不会顺手查了下WIKI)。小细节不要那么在意啦,还是速度说下下一种吧。

    方法3其实应该算是方法2的变种。既然用指针能访问每个byte,那除了指针外还有什么方法也能达到同样效果呢?

    C里面有个叫共用体(union)的特殊类型,此类型的神奇效果是其字段共用一个内存位置,也就是说一个UInt32在内存中是可以和4个Byte重叠在一起的。如果我们可以用这种方法的话,不就意味着可以直接读到分割的结果了么?那么,唯一的问题是共用体在C#中没见过啊?没有一个类型叫union的玩意?

    其实,这玩意是存在的。只是除了P/Invoke调用以外实在太无存在干了。其实就是通过StructLayoutAttribute指定手动内存布局,并通过FieldOffsetAttribute手动将内存布局重叠到一起。代码如下:

    [StructLayout(LayoutKind.Explicit)]
    internal struct UIntByteConverter
    {
        [FieldOffset(0)]
        public uint Source;
    
        [FieldOffset(0)]
        public byte part4;
    
        [FieldOffset(1)]
        public byte part3;
    
        [FieldOffset(2)]
        public byte part2;
    
        [FieldOffset(3)]
        public byte part1;
    }

    然后接下来的事情就简单了,也就是对Source赋值完直接读取结果罢了。

    那么,本篇博文就这么结束了。有没有觉得什么东西怪怪的?

    有么?

    没有么?

    有么?

    这是凑字数么?

    这不是凑字数么?

    ……

    ……

    ……

    ……

    好吧,其实从标题开始我就没说过只有三种方法嘛。至少还有种方法我是见别人有这么用过(不过对一个不太水的程序员来说,应该是毫无意义的方法来着)。

    方法0(对,我就是喜欢从零数起,你咬我啊):转成字符串然后拆分字符串再转回来。

    一看就知道效率很低,而且其实写起来也很麻烦……

    var temp=ipt.ToString("X8");
    byte p1=byte.Parse(temp.Substring(0, 2), NumberStyles.HexNumber);
    byte p2=byte.Parse(temp.Substring(2, 2), NumberStyles.HexNumber);
    byte p3=byte.Parse(temp.Substring(4, 2), NumberStyles.HexNumber);
    byte p4=byte.Parse(temp.Substring(6, 2), NumberStyles.HexNumber);

    那么,以上方法的效率如何呢?说实话除了方法3要多一个对象创建而方法0完全坑爹外差别好小。对一个没停药的人来说方法1完全够了(不过我总觉得某些方面方法3也有奇效)。具体如何请自行下载代码自行跑测试吧。

    代码点我下载

  • 相关阅读:
    International Collegiate Programming Contest 2019 Latin American Regional Contests E. Eggfruit Cake(思维/尺取)
    Codeforces Round #673 (Div. 2) C. k-Amazing Numbers(思维)
    2020 计蒜之道 预赛 第一场 A、B
    生成字符画
    我对目前国内教学的看法
    Stm32 调试时发生HardFault_Handler
    python异常处理
    windows nfs客户端配置
    linux服务器删除文件后df -h查看文件系统占比无变化
    python ssh小程序
  • 原文地址:https://www.cnblogs.com/Nyarlathotep/p/3589112.html
Copyright © 2020-2023  润新知