用過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
程序員