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


程序員

相關文章
相關標籤/搜索