C#不用union,而是有更好的方式實現

来源:https://www.cnblogs.com/hjsstudio/archive/2018/05/24/9082218.html
-Advertisement-
Play Games

用過C/C++的人都知道有個union,特別好用,似乎char數組到short,int,float等的轉換無所不能,也確實是能,並且用起來十分方便。那C#為什麼沒有這個關鍵字呢?怎麼實現這個功能?其實C#只是沒有了這個關鍵字,但是功能是能實現的,而且也是非常方便,並且是安全的。網上有人用Struct ...



用過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



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Thread (ParameterizedThreadStart) 初始化 Thread 類的新實例,指定允許對象線上程啟動時傳遞給線程的委托。 Thread (ThreadStart) 初始化 Thread 類的新實例。 由 .NET Compact Framework 支持。 Thread (P ...
  • 先上結果: 之前 在公司業務中用過java+Selenium+ChromeDriver ,使用起來非常順手,可以完美模擬真實的用戶瀏覽行為。最近休息的時候想用C#也試一下,於是有了本文。 實現原理一樣,只是由java換成了C#。(ps:個人感覺就業務開發代碼來說,熟悉之後兩種語言可以無縫切換。) 事 ...
  • 百度,一家讓人既愛又恨的企業,血友吧貼吧被賣,魏則西事件的持續發酵,一時間將百度推到了輿論的風口浪尖上。是非對錯,我們在這裡也不多做評判,本文呢為大家整理了百度開源的70+項目,看看有沒有感興趣的。本文內容綜合整理自oschina、github。 1. JavaScript圖表庫 ECharts E ...
  • 為了減少由於單個請求掛掉而拖垮整站的情況發生,給所有請求做統計是一個不錯的解決方法,通過觀察哪些請求的耗時比較長,我們就可以找到對應的介面、代碼、數據表,做有針對性的優化可以提高效率。在 asp.net web api 中我們可以通過註冊一個 DelegatingHandler 來實現該功能。那在  ...
  • 1、什麼是編程語言? 程式員與電腦溝通的介質 2、什麼是編程? 程式員基於某種編程語言的語法格式將想讓電腦所做的事寫到文件中讓電腦執行,編程的結果就是文件,文件的內容就是程式; 3、為什麼要編程? 讓電腦代替人類工作,解放人力 4,、電腦硬體基礎 (1)、什麼是x86-64位? x86是c ...
  • 正確開啟虛擬化的方式 列表如ListBox,ListView,TreeView,GridView等,開啟虛擬化 直接在模板中,設置CanContentScroll="True" 如模板中未設置CanContentScroll屬性,可以在列表添加屬性ScrollViewer.CanContentScr ...
  • 回到目錄 Invoke和BeginInvoke都是調用委托實體的方法,前者是同步調用,即它運行在主線程上,當Invode處理時間長時,會出現阻塞的情況,而BeginInvod是非同步操作,它會從新開啟一個線程,所以不會租塞主線程,在使用BeginInvoke時,如果希望等待執行的結果 ,可以使用End ...
  • .Net Framework中,把資源分為托管資源和非托管資源兩大類, 托管資源指可以通過.Net Frame垃圾回收器進行回收的資源,主要是指分配在托管堆上你的記憶體資源,這類資源的回收是不需要人工干預,.Net Framework的垃圾回收器會在合適的時刻進行回收,程式也可以主動調用GC.Coll ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...