`
lovnet
  • 浏览: 6876619 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

Marshal.SizeOf和sizeof的区别

阅读更多

Sizeof在非Unsafe环境下只能用于预定义的一系列类型,如Int,Short等等。而在Unsafe环境下,sizeof可以被用于值类型,但是值类型中不可以有引用类型,否则C#编译器会报错:

error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('SizeOf.Program.MyStruct')

而Marshal.SizeOf则是获得该类型被Marshal(转换,通常翻译为列集,指数据从一种类型转换到另外一种类型)到对应的非托管类型的大小。和sizeof不同,Marshal.SizeOf允许用在含有引用类型的值类型上:

   1: [StructLayout(LayoutKind.Sequential)]
   2: struct MyStruct
   3: {
   4:     string s;
   5: }

Marshal.SizeOf(MyStruct)结果为4或者8,因为string被Marshal成char*。

如果用在不含有引用类型的值类型上,其结果也有可能和sizeof完全不一样,如对于下面的值类型:

   1: struct MyStruct
   2: {
   3:     char b;
   4: }

sizeof(MyStruct)为2,而Marshal.SizeOf(typeof(MyStruct))结果则为1。这是因为在.NET中char总是Unicode,而缺省情况下char会被Marshal成8位的Ansi字符,因此结果不同。

反之,如果我们指定这个char被Marshal成short值(也就是UTF16),如下:

   1: [StructLayout(LayoutKind.Sequential)]
   2: struct MyStruct
   3: {
   4:     [MarshalAs(UnmanagedType.I2)]
   5:     char b;
   6: }

那么sizeof和Marshal.SizeOf结果均为2。MarshalAs这个Attribute可以影响Marshal.SizeOf的结果,而不能影响sizeof的结果。

一个有意思的情况是,如果值类型不含任何成员,如下:

   1: struct MyStruct
   2: {
   3: }

Sizeof和Marshal.SizeOf结果均为1,而不是0。这个结果和C++的结果是一致的。原因很简单:如果声明一个这样的数组,如果元素大小为0的话,那么每个元素都具有相同的地址,这是不为C++标准所允许的,和正常的非0的情况也不一致。.NET在这里采用和c++相同的规则,也认为空的值类型大小为1。

最后需要注意的是,如果MyStruct是模板:

   1: struct MyStruct<t></t>
   2: {
   3:     T a;
   4: }

如果对Marshal.SizeOf传入MyStruct或者MyStruct<int>这样的类型,则抛出ArgumentException,因为Marshal.SizeOf完全不支持泛型。这个是历史遗留问题,从本质上来讲实例化的模板类型(MyStruct<int>)应该是支持的,据说当时主要是没有时间加上对模板的支持。</int></int>

同样的,sizeof也不支持模板类型,而且连MyStruct<int>这样子的类型也不支持。C#编译器会对sizeof(MyStruct<int>)报错:error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('SizeOf.Program.MyStruct<int>')</int></int></int>


作者:张羿
转载请注明出处

分享到:
评论

相关推荐

    Marshal类的使用

    在.NET框架中, Marshal 类是一个强大的工具,它提供了在托管代码(Managed Code)和非托管代码(Unmanaged Code)之间进行数据转换和交互的能力。Marshal类属于System.Runtime.InteropServices命名空间,是.NET平台...

    wav资料 内容和程序

    IntPtr structPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WavHeader))); Marshal.Copy(bytes, 0, structPtr, Marshal.SizeOf(typeof(WavHeader))); WavHeader header = (WavHeader)Marshal....

    dotnet C# 将 Byte 二进制数组使用不安全代码快速转换为 int 或结构体数组.rar

    Buffer.BlockCopy((byte*)&structArray[i], 0, byteCurrent, Marshal.SizeOf(), Marshal.SizeOf()); byteCurrent += Marshal.SizeOf(); } } return new MyStruct[count]; } ``` 这个方法中,我们使用`Marshal....

    C#结构与C++之间转换.pdf

    IntPtr structPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Operator))); Marshal.Copy(bytes, 0, structPtr, Marshal.SizeOf(typeof(Operator))); Operator operatorObj = (Operator)Marshal....

    C#中结构体struct和字节数组Byte的之间的转换函数

    此方法中,`Marshal.SizeOf`用来获取结构体的大小;`Marshal.AllocHGlobal`分配内存空间;`Marshal.StructureToPtr`将结构体复制到指针所指向的内存区域;`Marshal.Copy`则负责将内存中的数据复制到字节数组中。 ##...

    C#结构体和C++字节数组的转换

    int size = Marshal.SizeOf(structObj); byte[] bytes = new byte[size]; IntPtr structPtr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(structObj, structPtr, false); Marshal.Copy(structPtr, ...

    官方VB.net WM_COPYDATA进行进程间资源共享的例子

    Dim lParam As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(cds)) Marshal.StructureToPtr(cds, lParam, False) SendMessage(hWndReceiver, &H4A, 0, lParam) ' WM_COPYDATA 消息码 Marshal.FreeHGlobal(lParam) ...

    动态改变IP

    IntPtr intptrStruct = Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI)); // Converting structure to IntPtr Marshal.StructureToPtr(struct_IPI, intptrStruct, true); bool iReturn = ...

    C#与C++通讯字节流转换结构体

    int size = Marshal.SizeOf(objStruct); byte[] buffer = new byte[size]; IntPtr ipStruct = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(objStruct, ipStruct, false); Marshal.Copy(ipStruct, ...

    c# ini读写操作

    IntPtr pReturnedString = Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char)); uint bytesReturned = GetPrivateProfileSectionNames(pReturnedString, MAX_BUFFER, iniFile); if (bytesReturned != 0) {...

    C# 中改变显示器的分辨率和刷新频率

    dm.dmSize= (short)Marshal.SizeOf(typeof(DEVMODE)); dm.dmPelsWidth = 1024; dm.dmPelsHeight= 768; dm.dmDisplayFrequency=85; dm.dmFields = DEVMODE.DM_PELSWIDTH | DEVMODE.DM_PELSHEIGHT | DEVMODE.DM_...

    size_of

    通过`sizeof`和`Marshal.SizeOf`,开发者可以获取类型或实例在内存中占用的空间,从而进行更精细的内存管理。不过,需要注意内存对齐、平台差异等因素对实际大小的影响。在实际应用中,合理利用这些知识可以提升程序...

    在Windows下让不同用户使用不同的分辨率

    dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE)); if (chMode == 1) { dm.dmPelsWidth = 1600; dm.dmPelsHeight = 1024; dm.dmDisplayFrequency = 85; } else if (chMode == 2) { dm.dmPelsWidth = 1024; dm....

    Linux下.net core版本加载海康SDK库失败问题处理

    var ptrByteArray1Size = Marshal.SizeOf(ptrByteArray1); var ptrByteArray1Intptr = Marshal.AllocHGlobal(ptrByteArray1Size); Marshal.StructureToPtr(ptrByteArray1, ptrByteArray1Intptr, true); ...

    如何在程序中切换输入法程序(

    SendInput(1, New INPUT() {input}, Marshal.SizeOf(input)) '按下Space键 input.ki.wVk = &H20 'Space键的虚拟键码 SendInput(1, New INPUT() {input}, Marshal.SizeOf(input)) '释放Space键 input.ki....

    C#打开软键盘

    SendInput(1, new INPUT[] { input }, Marshal.SizeOf(input)); input.ki.wVk = (ushort)Keys.R; input.ki.dwFlags = 0; // Key down SendInput(1, new INPUT[] { input }, Marshal.SizeOf(input)); input....

    C#—EMguCV Marshal

    IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(p)); try { // 将结构体数据复制到非托管内存 Marshal.StructureToPtr(p, ptr, false); // 读取非托管内存中的数据 PERSON pFromPtr = (PERSON)Marshal....

    C#byte数组结构体互相转换示例.zip

    这里使用了`Marshal.SizeOf`计算结构体的大小,并通过`Marshal.StructureToPtr`将结构体复制到内存的字节数组中。 3. **字节数组转结构体**:创建一个方法将字节数组还原为结构体。 ```csharp public static ...

    C#打开exe,doc,excel程序并监视其是否关闭

    si.cb = Marshal.SizeOf(si); StringBuilder sb = new StringBuilder(@"C:\WINDOWS\notepad.exe c:\1.txt"); if (CreateProcess(null,sb, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, ref si...

    C#结构体指针的定义及使用详解

    IntPtr intptr = Marshal.AllocHGlobal(Marshal.SizeOf(vga)); Marshal.StructureToPtr(vga, intptr, true); // 将结构体复制到非托管内存 // 在此发送 intptr 指针给目的方 Marshal.FreeHGlobal(intptr); // 释放...

Global site tag (gtag.js) - Google Analytics