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\t%d\t%d\t%d\n", chArr[0], chArr[1], chArr[2], chArr[3]);
    
    float f2 = 0.00f;
    memcpy(&f2, chArr, sizeof(float));
    printf("%0.2f\n", f2);
    
    float f3 = *(float *)chArr;
    printf("%0.2f\n", f3);

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

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

    float f2 = BitConverter.ToSingle(b, 0);
    Console.WriteLine("f2\t: {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


程序员

相关文章
相关标签/搜索