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
C#不用union,而是有更好的方式实现的更多相关文章
- C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路
C#不用union,而是有更好的方式实现 用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...
- 代码规范(RL-TOC)用更合理的方式写 JavaScript
代码可以改变世界 不规范代码可以毁掉世界 只有先学会写规范的代码,才可以走的更远 编程语言之间有很多编程规范都是通用: 命名 不要用语言不明的缩写,不用担心名字过长,名字一定要让别人知道确切的意思; ...
- 【译】更快的方式实现PHP数组去重
原文:Faster Alternative to PHP’s Array Unique Function 概述 使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一 ...
- [C#] 用一种更优美的方式来替换掉又多又长的switch-case代码段
switch-case语句是我们编码过程中常用的一种分支语句.然而正所谓成也萧何败萧何,每当我们向一个已经拥有了成百上千行的switch-case代码段中添加新的case分支的时候,我们是否有过为代码 ...
- 更快的方式实现PHP数组去重(转)
概述 使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一个拥有唯一值的数组.这个函数大多数情况下都能工作得很好.但是,如果你尝试在一个大的数组里使用array_u ...
- 更快的方式实现 PHP 数组去重
概述 使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一个拥有唯一值的数组.这个函数大多数情况下都能工作得很好.但是,如果你尝试在一个大的数组里使用array_u ...
- 不用 Notepad++,还有更牛逼的选择!
来源:oschina.net/news/110987/no-notepad-plus-plus 这两天 Notepad++ 牛逼了,然后引发了大家的关注,具体事件内容请大家自行百度,其实作为文本编辑工 ...
- 少年,是时候换种更优雅的方式部署你的php代码了
让我们来回忆下上次你是怎么发布你的代码的: 1. 先把线上的代码用ftp备份下来 2. 上传修改了的文件 3. 测试一下功能是否正常 4. 网站500了,赶紧用备份替换回去 5. 替换错了/替换漏了 ...
- [改善Java代码]集合运算时使用更优雅的方式
在初中代数中,我们经常会求两个集合的并集.交集.差集等,在Java中也存在着此 类运算,那如何实现呢? 一提到此类集合操作,大部分的实现者都会说:对两个集合进行遍历,即可求出结果.是的,遍历可以实现并 ...
随机推荐
- C++中的浅拷贝和深拷贝
浅拷贝(shallow copy)与深拷贝(deep copy)对于值拷贝的处理相同,都是创建新对象,但对于引用拷贝的处理不同,深拷贝将会重新创建新对象,返回新对象的引用字.浅拷贝不会创建新引用类型. ...
- Js语言的奇怪特性
var a = .3 - 2; console.log(a); a = 0.099999998 而不是0.1,是不是很奇怪?
- iOS codeview
1.环境配置 oclint:http://oclint.org/ xcpretty:https://github.com/supermarin/xcpretty 使用Mac安装xcpretty过程可能 ...
- redis中multi和pipeline区别以及效率(推荐使用pipeline)
手册得知 pipeline 只是把多个redis指令一起发出去,redis并没有保证这些指定的执行是原子的:multi相当于一个redis的transaction的,保证整个操作的原子性,避免由于中途 ...
- springmvc中Controller方法的返回值
1.1 返回ModelAndView controller方法中定义ModelAndView对象并返回,对象中可添加model数据.指定view. 1.2 返回void 在controller方法形参 ...
- JTemplate学习(一)
使用模板绑定数据,可以嵌套循环 参考:http://www.doc88.com/p-6621237324128.html <!DOCTYPE html PUBLIC "-//W3C// ...
- 记录java版本不兼容的坑,(kafka运行报错)
启动kafka报错 错误原因是: 由较高版本的jdk编译的java class文件 试图在较低版本的jvm上运行的报错 解决办法是: 查看java版本 C:\Users\Administrator&g ...
- 函数中返回char *类型
记录一次比较容易引起混淆的地方. #include <stdio.h> char *str(void) { return "nihao\n"; } int main() ...
- tp5允许跨域
header("Access-Control-Allow-Origin: *"); 放在命名空间之后
- apicloud管理
以下所有操作都是指“apicloud”平台下的管理: 1. 一定要记得备份证书.证书不是因为你记得别名和密码就能还原的.因为apicloud是服务器session存数据,千万不要打开多个app操作页面 ...