最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C# 中的 sizeof 與非托管類型約束全解析

 更新時間:2026年03月30日 09:02:00   作者:MutoKazuo  
在 C# 中,sizeof 是一個用于獲取非托管類型(Unmanaged Type)在內(nèi)存中所占字節(jié)數(shù)(Byte)的運算符,這篇文章主要介紹了深入理解 C# 中的 sizeof 與非托管類型約束,需要的朋友可以參考下

它的作用是在編譯時獲取非托管類型所占用的字節(jié)數(shù)。它就像是內(nèi)存的“空間丈量尺”,告訴你這個類型在內(nèi)存里到底占了多大的地兒。

在 C# 中,sizeof 是一個用于獲取非托管類型(Unmanaged Type)內(nèi)存中所占字節(jié)數(shù)(Byte)的運算符。它的本質(zhì)是編譯器指令,在編譯階段就能確定數(shù)值。

1. 它到底在查什么?

sizeof 的核心在于內(nèi)存布局(Memory Layout)。計算機存儲數(shù)據(jù)時,不同的數(shù)據(jù)類型需要占用不同大小的連續(xù)空間。sizeof 告訴程序:如果要為一個變量分配空間,到底需要切出多大的一塊內(nèi)存。

2. 核心語法與約束

sizeof 的用法非常簡單,但受限于 C# 的安全機制:

  • 內(nèi)置基礎(chǔ)類型:可以直接使用,如 sizeof(int)。
  • 自定義結(jié)構(gòu)體:必須在 unsafe(不安全)上下文中使用。
  • 局限性:它不能用于引用類型(Reference Type),如 class,因為引用類型的大小在堆棧上只是一個指針大小,其實際內(nèi)容在堆中分配,且受垃圾回收(GC)影響,布局不固定。

流程圖:sizeof 的執(zhí)行邏輯

3. 代碼示例

基礎(chǔ)用法

對于內(nèi)置類型,sizeof 返回的是可預(yù)見的結(jié)果:

Console.WriteLine(sizeof(byte));   // 輸出: 1
Console.WriteLine(sizeof(int));    // 輸出: 4
Console.WriteLine(sizeof(long));   // 輸出: 8
Console.WriteLine(sizeof(double)); // 輸出: 8

進(jìn)階用法:自定義結(jié)構(gòu)體

當(dāng)處理自定義結(jié)構(gòu)時,需要考慮內(nèi)存對齊(Memory Alignment)。

using System;
struct MyStruct
{
    public byte A; // 1 byte
    public int B;  // 4 bytes
}
class Program
{
    static void Main()
    {
        // 必須開啟 unsafe 編譯選項
        unsafe
        {
            // 結(jié)果是 8,而不是 5。
            // 因為編譯器為了 CPU 讀取效率,會對字段進(jìn)行填充(Padding)。
            Console.WriteLine($"結(jié)構(gòu)體大小: {sizeof(MyStruct)}");
        }
    }
}

4. 常用使用場景

  • 非托管互操作(Interop):當(dāng)你調(diào)用 C/C++ 寫的動態(tài)鏈接庫(DLL)時,需要精確告訴系統(tǒng)你要傳遞多大的數(shù)據(jù)塊。
  • 序列化與二進(jìn)制讀寫:在高性能場景下,直接操作 byte[] 數(shù)組時,通過 sizeof 確定偏移量。
  • 內(nèi)存池分配:預(yù)先申請一塊內(nèi)存空間,計算總?cè)萘繒r使用。
  • 性能優(yōu)化:通過 sizeof 觀察結(jié)構(gòu)體對齊情況,減少內(nèi)存碎片的浪費。

除了基礎(chǔ)的內(nèi)存分配,在資深軟件工程師眼中,sizeof 更多用于底層優(yōu)化精密控制

A. 棧上內(nèi)存分配 (stackalloc)

在追求極致性能的場景(如解析高頻金融數(shù)據(jù)),我們避開堆內(nèi)存,直接在棧上開辟空間。

// 申請 100 個 int 大小的棧空間
Span<int> numbers = stackalloc int[100];
// 在底層邏輯中,它等同于申請了 100 * sizeof(int) 字節(jié)

B. 泛型約束中的內(nèi)存計算

在 C# 7.3 之后,我們可以使用 where T : unmanaged 約束。配合 sizeof,可以編寫極其通用的高性能代碼。

public unsafe void CopyData<T>(T* source, T* destination, int count) where T : unmanaged
{
    // 自動根據(jù) T 的類型計算需要復(fù)制的字節(jié)總數(shù)
    long totalBytes = (long)count * sizeof(T);
    Buffer.MemoryCopy(source, destination, totalBytes, totalBytes);
}

C. 固定內(nèi)存塊偏移 (Fixed Memory Offset)

當(dāng)你在處理復(fù)雜的二進(jìn)制協(xié)議(如網(wǎng)絡(luò)封包、視頻解碼)時,sizeof 是計算偏移量的唯一準(zhǔn)繩。

sizeof(sbyte)1
sizeof(byte)1
sizeof(short)2
sizeof(ushort)2
sizeof(int)4
sizeof(uint)4
sizeof(long)8
sizeof(ulong)8
sizeof(char)2
sizeof(float)4
sizeof(double)8
sizeof(decimal)16
sizeof(bool)1

5. Marshal.SizeOf

在實際開發(fā)中,Marshal.SizeOf 最經(jīng)典的舞臺就是 Win32 API 調(diào)用。

很多 Windows 底層的函數(shù)要求你傳入一個結(jié)構(gòu)體,并且在這個結(jié)構(gòu)體的第一個字段里,你必須明確告訴系統(tǒng):“這個結(jié)構(gòu)體本人占用了多少字節(jié)”。如果這個數(shù)字填錯了,系統(tǒng)為了安全會直接拒絕執(zhí)行。

1. 為什么要運行時測量?

Windows API 設(shè)計時為了向前兼容,經(jīng)常會在同一個結(jié)構(gòu)體的后續(xù)版本中增加字段。系統(tǒng)通過檢查你傳入的 Size(大?。﹣砼袛嗄闶褂玫氖悄囊粋€版本的結(jié)構(gòu)體,從而決定如何處理內(nèi)存。

2. 核心場景:獲取系統(tǒng)托盤圖標(biāo)信息

假設(shè)我們要獲取 Windows 任務(wù)欄通知區(qū)域(托盤)的圖標(biāo)信息,會用到 NOTIFYICONDATA 結(jié)構(gòu)體。

using System;
using System.Runtime.InteropServices;
// 定義符合 Win32 布局的結(jié)構(gòu)體
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct NOTIFYICONDATA
{
    public int cbSize;        // 結(jié)構(gòu)體本身的大?。P(guān)鍵?。?
    public IntPtr hWnd;       // 窗口句柄
    public uint uID;          // 圖標(biāo) ID
    public uint uFlags;       // 標(biāo)志位
    public uint uCallbackMessage;
    public IntPtr hIcon;      // 圖標(biāo)句柄
    // ... 其他字段省略
}
class Program
{
    static void Main()
    {
        NOTIFYICONDATA data = new NOTIFYICONDATA();
        // 場景:初始化結(jié)構(gòu)體時,必須告知系統(tǒng)該結(jié)構(gòu)體的大小
        // 這里不能用 sizeof(NOTIFYICONDATA),因為在沒有 unsafe 的環(huán)境下無法編譯
        // 且 Marshal.SizeOf 會考慮 CharSet 帶來的字符編碼寬度差異
        data.cbSize = Marshal.SizeOf(typeof(NOTIFYICONDATA));
        Console.WriteLine($"結(jié)構(gòu)體在托管內(nèi)存中的大小推算為: {data.cbSize} 字節(jié)");
        // 模擬調(diào)用 Win32 API
        // Shell_NotifyIcon(NIM_ADD, ref data);
    }
}

3. 為什么這個例子不用 sizeof?

  1. 無需 unsafeMarshal.SizeOf 可以在普通的托管代碼中運行,不需要開啟項目的“允許不安全代碼”開關(guān)。
  2. 封送感知 (Marshaling Awareness)Marshal.SizeOf 會考慮 StructLayout 屬性。例如,如果結(jié)構(gòu)體里有 string,sizeof 根本無法處理,而 Marshal.SizeOf 會根據(jù)你指定的 CharSet(如 Unicode 占 2 字節(jié),Ansi 占 1 字節(jié))來計算它轉(zhuǎn)化成 C 語言格式后的大小。

4. 流程圖:Marshal.SizeOf 如何在運行時工作

5. sizeof vs Marshal.SizeOf

它位于 System.Runtime.InteropServices 命名空間下。只要你安裝了 .NET SDK,就可以直接通過 using 引用它。

  • 本質(zhì)區(qū)別
    • sizeof:**編譯時(Compile-time)**指令。它直接硬編碼數(shù)值到程序中,速度極快,但只能用于非托管類型。
    • Marshal.SizeOf:運行時(Runtime)方法。它通過反射(Reflection)去測量對象在內(nèi)存布局(特別是轉(zhuǎn)換為非托管格式后)的大小,支持 struct 實例,也能處理一些被裝箱的對象,但性能開銷比 sizeof
特性sizeofMarshal.SizeOf
性能極高(等同于直接寫數(shù)字)一般(有運行時開銷)
上下文要求涉及自定義結(jié)構(gòu)需 unsafe無需 unsafe
靈活性只能用類型名,不能用變量名可以直接傳入變量實例
主要目的算偏移量、算指針位移調(diào)用 Win32 API、處理復(fù)雜封送

6. 易混淆

  • 句柄 (Handle/IntPtr):可以理解為系統(tǒng)資源的“代號”或“門票”。在 64 位系統(tǒng)下,它的大小等同于 long(8 字節(jié))。
  • 封送 (Marshaling):將 C# 中的對象搬運到內(nèi)存緩沖區(qū),并轉(zhuǎn)換成 C/C++ 能看懂的格式的過程。
  • StructLayout (LayoutKind.Sequential):強制要求編譯器按照你在代碼里寫字段的順序來排列內(nèi)存,不要為了優(yōu)化而打亂順序,否則 Windows 系統(tǒng)會讀錯數(shù)據(jù)。
  • 非托管類型 (Unmanaged Type):指不需要垃圾回收器(GC)管理的類型。包括 sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, 枚舉, 以及只包含這些類型的結(jié)構(gòu)體。
  • 內(nèi)存對齊 (Memory Alignment):CPU 讀取內(nèi)存時不是一個字節(jié)一個字節(jié)讀的,而是以“塊”(如 4 或 8 字節(jié))為單位。為了提高讀取速度,編譯器會在數(shù)據(jù)結(jié)構(gòu)之間插入一些無用的空字節(jié),使數(shù)據(jù)起始地址落在塊的邊界上。
  • 填充 (Padding):內(nèi)存對齊過程中自動添加的空閑字節(jié)。
  • unsafe 上下文:C# 默認(rèn)是內(nèi)存安全的,不允許直接操作地址。通過 unsafe 關(guān)鍵字,你可以在特定區(qū)域內(nèi)像 C 語言一樣直接操作指針和查看原始內(nèi)存布局。

到此這篇關(guān)于C# 中的 sizeof 與非托管類型約束全解析的文章就介紹到這了,更多相關(guān)C# sizeof 與非托管類型約束內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • c# 圓形識別方案和直線識別方案的參考示例

    c# 圓形識別方案和直線識別方案的參考示例

    這篇文章主要介紹了c# 圓形識別方案和直線識別方案的實現(xiàn)示例,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • C#基于Miniblink控件編寫一個簡易的瀏覽器

    C#基于Miniblink控件編寫一個簡易的瀏覽器

    miniblink是一款精簡小巧的瀏覽器控件,基于chromium精簡而成,是市面上最小巧的chromium內(nèi)核控件沒有之一,本文將結(jié)合C#和Miniblink編寫一個簡易的瀏覽器,感興趣的可以了解下
    2024-01-01
  • C# Email郵件發(fā)送功能 找回或重置密碼功能

    C# Email郵件發(fā)送功能 找回或重置密碼功能

    這篇文章主要為大家詳細(xì)介紹了C# Email郵件發(fā)送功能,找回或重置密碼功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • C#使用Linq to XML進(jìn)行XPath查詢的代碼實現(xiàn)

    C#使用Linq to XML進(jìn)行XPath查詢的代碼實現(xiàn)

    最近在用到HtmlAgliltyPack進(jìn)行結(jié)點查詢時,發(fā)現(xiàn)這里選擇結(jié)點使用的是XPath,所以這里總結(jié)一下在C#中使用XPath查詢XML的方法,習(xí)慣了用Linq,這里也是用的Linq to xml的,需要的朋友可以參考下
    2024-08-08
  • 在C# .NET Core中繪制Chart圖表并導(dǎo)出到PDF的實現(xiàn)方法

    在C# .NET Core中繪制Chart圖表并導(dǎo)出到PDF的實現(xiàn)方法

    正好最近的項目需要在后端繪制Chart圖標(biāo)并進(jìn)行導(dǎo)出,查閱相關(guān)資料后想著記錄以下,本文將詳細(xì)介紹在.NET Core環(huán)境中如何繪制Chart圖表并將其導(dǎo)出到PDF文檔中,并分析這種實現(xiàn)方式的技術(shù)價值和應(yīng)用場景,需要的朋友可以參考下
    2025-10-10
  • C#如何利用反射將枚舉綁定到下拉框詳解

    C#如何利用反射將枚舉綁定到下拉框詳解

    這篇文章主要給大家介紹了關(guān)于C#如何利用反射將枚舉綁定到下拉框的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧
    2018-07-07
  • C#使用OpenCvSharp實現(xiàn)透視變換功能

    C#使用OpenCvSharp實現(xiàn)透視變換功能

    這篇文章主要為大家詳細(xì)介紹了C#如何使用OpenCvSharp實現(xiàn)透視變換的功能,文中的示例代碼簡潔易懂,具有一定的學(xué)習(xí)價值,需要的小伙伴可以參考下
    2023-11-11
  • C#判斷字符串不等于空的方法小結(jié)

    C#判斷字符串不等于空的方法小結(jié)

    在C#中,要判斷一個字符串是否不等于空(即它既不是null也不是空字符串""),方法有如下幾種,文中通過代碼示例講解的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-06-06
  • C#8.0新語法using?declaration

    C#8.0新語法using?declaration

    這篇文章介紹了C#8.0的新語法using?declaration,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • C#簡單實現(xiàn)在網(wǎng)頁上發(fā)郵件的案例

    C#簡單實現(xiàn)在網(wǎng)頁上發(fā)郵件的案例

    本文分享一個C#利用SMTP發(fā)送郵件的案例,提供了前后臺代碼,方便大家學(xué)習(xí)。
    2016-03-03

最新評論

德令哈市| 宝坻区| 抚顺市| 齐河县| 铁岭市| 寻甸| 清远市| 忻州市| 宿松县| 通州区| 烟台市| 安多县| 丰原市| 宝坻区| 鲜城| 五原县| 女性| 基隆市| 甘肃省| 临西县| 革吉县| 鄢陵县| 招远市| 饶阳县| 沙河市| 盐边县| 连江县| 和林格尔县| 青海省| 诏安县| 鹿泉市| 鄂州市| 壶关县| 蒙城县| 鄂托克旗| 潼关县| 乐亭县| 资兴市| 图木舒克市| 东港市| 台州市|