zoukankan      html  css  js  c++  java
  • C#不用union,而是有更好的方式实现


    用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便。
    那C#为什么没有这个关键字呢?怎么实现这个功能?其实C#只是没有了这个关键字,但是功能是能实现的,而且也是非常方便,并且是安全的。
    网上有人用StructLayout特性来实现union,也确实是实现了一些功能。
    比如:
    C/C++:
        union {
            unsigned char ch
            short ;
            int i;
        };
    C#:
        [StructLayout(LayoutKind.Explicit)]
        public struct Class1
        {
            [FieldOffset(0)]
            public byte b;

            [FieldOffset(0)]
            public short s;

            [FieldOffset(0)]
            public int i;
        }
    就可以实现。
    但是我要是写个:
        union {
            unsigned char ch[4];
            int i;
            float f;
        } temp;
    硬是用C#没有模拟出来,估计我还没有找着合适的方法。因为我写
        [StructLayout(LayoutKind.Explicit)]
        public struct Class1
        {
            [FieldOffset(0)]
            public byte[4] b;

            [FieldOffset(0)]
            public short s;

            [FieldOffset(0)]
            public int i;
        }
    这玩意是编译不通过的。然后折腾了半天,没有折腾出来。后来又回到C/C++想了一番,似乎有些认识。
    C/C++用union其实就是使用同一块内存存储不同类型的数据,说白了,就是一块公用的内存,你用啥读取出来就是啥内容。其实计算机中的内存本身也就是这样,你定义一个int i;然后计算机会在内存栈上开辟一块空间,并且这块内存指明了是int类型,但是我们经常看到(int)data,(int*)pt等操作,说明可以强制转换。强制转换不是说把这几块内存的值改变了,只是临时改变了读取方式,然后用这种方式读取这块内存。那这样说来是不是也可以不用union来实现char数组与其他类型之间的转换,答案是必须可以。
    比如:
        unsigned char chArr[4] = "";
        float f1 = 45.56f;
        memcpy(chArr, &f1, sizeof(float));
        // 运行结果:113    61    54    66
        printf("%d %d %d %d ", chArr[0], chArr[1], chArr[2], chArr[3]);
        
        float f2 = 0.00f;
        memcpy(&f2, chArr, sizeof(float));
        printf("%0.2f ", f2);
        
        float f3 = *(float *)chArr;
        printf("%0.2f ", f3);

        char *pch = (char *)&f3;
        // 运行结果:113    61        54        66
        printf("%d %d %d %d ", pch[0], pch[1], pch[2], pch[3]);

    那好问题来了,C#怎么实现?
    那好,答案也来了。当然是用BitConvert。
    比如:
        float f = 45.56f;
        byte[] b = BitConverter.GetBytes(f);
        Console.WriteLine("bArr : {0} {1} {2} {3}", b[0], b[1], b[2], b[3]);

        float f2 = BitConverter.ToSingle(b, 0);
        Console.WriteLine("f2 : {0}", f2);
    完全木有问题啊,而且还安全。

    最后呢,咱们看看微软是怎么给咱实现的。

        // Converts a float into an array of bytes with length
        // four.
        [System.Security.SecuritySafeCritical]  // auto-generated
        public unsafe static byte[] GetBytes(float value)
        {
            Contract.Ensures(Contract.Result<byte[]>() != null);
            Contract.Ensures(Contract.Result<byte[]>().Length == 4);

            return GetBytes(*(int*)&value);
        }

        ...
        // Converts an int into an array of bytes with length
        // four.
        [System.Security.SecuritySafeCritical]  // auto-generated
        public unsafe static byte[] GetBytes(int value)
        {
            Contract.Ensures(Contract.Result<byte[]>() != null);
            Contract.Ensures(Contract.Result<byte[]>().Length == 4);

            byte[] bytes = new byte[4];
            fixed(byte* b = bytes)
                *((int*)b) = value;
            return bytes;
        }

    看见了吗?是不是跟上面的C/C++代码很像。其实就是C/C++代码。如果你看不到这段代码,也许你还真不知道,原来以前自己的C/C++代码被搬到了这里。但是微软的公司的代码可不是我写的C/C++那么简单的转换,微软程序员是做了安全检查的。你如果将3个byte的数组转换到float,那对不起,玩不了,你得补一个字节。

    好了,给大家附上微软C#开源的源代码地址:
    https://referencesource.microsoft.com/#mscorlib/system/bitconverter.cs,9108fa2d0b37805b


  • 相关阅读:
    记一次JAVA WEB项目解决XSS攻击的办法(亲测有效)
    常用oracle可重复执行的脚本模板
    mybatis配置文件查询参数的传递
    oracle xmltype导入并解析Excel数据 (五)中间表数据入库
    oracle xmltype导入并解析Excel数据 (四)特别说明
    oracle xmltype导入并解析Excel数据 (三)解析Excel数据
    oracle xmltype导入并解析Excel数据 (二)规则说明
    oracle xmltype导入并解析Excel数据 (一)创建表与序
    ipv4,ipv6起止地址判断,网段判断
    HTML li标签排列有空白间隙
  • 原文地址:https://www.cnblogs.com/hjsstudio/p/9082218.html
Copyright © 2011-2022 走看看