用过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,而是有更好的方式实现的更多相关文章

  1. C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路

    C#不用union,而是有更好的方式实现   用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...

  2. 代码规范(RL-TOC)用更合理的方式写 JavaScript

    代码可以改变世界 不规范代码可以毁掉世界 只有先学会写规范的代码,才可以走的更远 编程语言之间有很多编程规范都是通用: 命名 不要用语言不明的缩写,不用担心名字过长,名字一定要让别人知道确切的意思; ...

  3. 【译】更快的方式实现PHP数组去重

    原文:Faster Alternative to PHP’s Array Unique Function 概述 使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一 ...

  4. [C#] 用一种更优美的方式来替换掉又多又长的switch-case代码段

    switch-case语句是我们编码过程中常用的一种分支语句.然而正所谓成也萧何败萧何,每当我们向一个已经拥有了成百上千行的switch-case代码段中添加新的case分支的时候,我们是否有过为代码 ...

  5. 更快的方式实现PHP数组去重(转)

    概述 使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一个拥有唯一值的数组.这个函数大多数情况下都能工作得很好.但是,如果你尝试在一个大的数组里使用array_u ...

  6. 更快的方式实现 PHP 数组去重

    概述 使用PHP的array_unique()函数允许你传递一个数组,然后移除重复的值,返回一个拥有唯一值的数组.这个函数大多数情况下都能工作得很好.但是,如果你尝试在一个大的数组里使用array_u ...

  7. 不用 Notepad++,还有更牛逼的选择!

    来源:oschina.net/news/110987/no-notepad-plus-plus 这两天 Notepad++ 牛逼了,然后引发了大家的关注,具体事件内容请大家自行百度,其实作为文本编辑工 ...

  8. 少年,是时候换种更优雅的方式部署你的php代码了

    让我们来回忆下上次你是怎么发布你的代码的: 1. 先把线上的代码用ftp备份下来 2. 上传修改了的文件 3. 测试一下功能是否正常 4. 网站500了,赶紧用备份替换回去 5. 替换错了/替换漏了 ...

  9. [改善Java代码]集合运算时使用更优雅的方式

    在初中代数中,我们经常会求两个集合的并集.交集.差集等,在Java中也存在着此 类运算,那如何实现呢? 一提到此类集合操作,大部分的实现者都会说:对两个集合进行遍历,即可求出结果.是的,遍历可以实现并 ...

随机推荐

  1. C++中的浅拷贝和深拷贝

    浅拷贝(shallow copy)与深拷贝(deep copy)对于值拷贝的处理相同,都是创建新对象,但对于引用拷贝的处理不同,深拷贝将会重新创建新对象,返回新对象的引用字.浅拷贝不会创建新引用类型. ...

  2. Js语言的奇怪特性

    var a = .3 - 2; console.log(a); a = 0.099999998 而不是0.1,是不是很奇怪?

  3. iOS codeview

    1.环境配置 oclint:http://oclint.org/ xcpretty:https://github.com/supermarin/xcpretty 使用Mac安装xcpretty过程可能 ...

  4. redis中multi和pipeline区别以及效率(推荐使用pipeline)

    手册得知 pipeline 只是把多个redis指令一起发出去,redis并没有保证这些指定的执行是原子的:multi相当于一个redis的transaction的,保证整个操作的原子性,避免由于中途 ...

  5. springmvc中Controller方法的返回值

    1.1 返回ModelAndView controller方法中定义ModelAndView对象并返回,对象中可添加model数据.指定view. 1.2 返回void 在controller方法形参 ...

  6. JTemplate学习(一)

    使用模板绑定数据,可以嵌套循环 参考:http://www.doc88.com/p-6621237324128.html <!DOCTYPE html PUBLIC "-//W3C// ...

  7. 记录java版本不兼容的坑,(kafka运行报错)

    启动kafka报错 错误原因是: 由较高版本的jdk编译的java class文件 试图在较低版本的jvm上运行的报错 解决办法是: 查看java版本 C:\Users\Administrator&g ...

  8. 函数中返回char *类型

    记录一次比较容易引起混淆的地方. #include <stdio.h> char *str(void) { return "nihao\n"; } int main() ...

  9. tp5允许跨域

    header("Access-Control-Allow-Origin: *"); 放在命名空间之后

  10. apicloud管理

    以下所有操作都是指“apicloud”平台下的管理: 1. 一定要记得备份证书.证书不是因为你记得别名和密码就能还原的.因为apicloud是服务器session存数据,千万不要打开多个app操作页面 ...