用过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
程序员