随笔 - 90  文章 - 0 评论 - 94 阅读 - 60万

When we want to control the memory layout, we must use System.Runtime.InteropServices namespace, it contains some useful attributes such as StructLayoutAttribute, FieldOffsetAttribute and also some useful enum like LayoutKind.

复制代码
using System;
using System.Runtime.InteropServices;

namespace LearnCSharp
{

    [StructLayout(LayoutKind.Explicit, Size 
= 8)]
    
struct UnionTest
    {
        [FieldOffset(
0)]
        
public sbyte i8;

        [FieldOffset(
0)]
        
public Int16 i16;

        [FieldOffset(
0)]
        
public Int32 i32;

        [FieldOffset(
0)]
        
public Int64 i64; // the biggest field, 8 bytes, so Size = 8
    }

    
class Program
    {        
        
static void Main(string[] args)
        {
            UnionTest ut 
= new UnionTest();
            ut.i64 
= 0;
            ut.i8 
= 0x1;
            ut.i16 
|= 0x1000;
            ut.i32 
|= 0x10000000;
            Console.WriteLine(
"{0:x16}", ut.i64);
            
return;
        }
    }
}

复制代码

 

LayoutKind Enum has 3 members:
Sequential(good enough for general purpose)
The members of the object are laid out sequentially, in the order in which they appear when exported to unmanaged memory. The members are laid out according to the packing specified in StructLayoutAttribute.Pack, and can be noncontiguous.

Explict(for special layout, powerful but you have to type more code to specify each field)
The precise position of each member of an object in unmanaged memory is explicitly controlled. Each member must use the FieldOffsetAttribute to indicate the position of that field within the type.

Auto(use it when you don't want to expose it to unmanaged code)
The runtime automatically chooses an appropriate layout for the members of an object in unmanaged memory. Objects defined with this enumeration member cannot be exposed outside of managed code. Attempting to do so generates an exception.

In the code below, struct Rect1 and Rect2 has the same memory layout, we use explicit and sequential only for demonstration.

 

复制代码
using System;
using System.Runtime.InteropServices;

namespace LearnCSharp
{
    [StructLayout(LayoutKind.Sequential)]
    
public struct Point
    {
        
public int x;
        
public int y;
    }

    
// Use LayoutKind.Sequential and Pack to make the memory layout same as unmanaged code
    [StructLayout(LayoutKind.Sequential, Pack=4)]    
    
public struct Rect1
    {        
        
public int left;       
        
public int top;
        
public int right;
        
public int bottom;
    }

    
// Use explicit offset to make the memory layout same as unmanaged code
    [StructLayout(LayoutKind.Explicit)]
    
public struct Rect2
    {        
        [FieldOffset(
0)]
        
public int left;
        [FieldOffset(
4)]
        
public int top;
        [FieldOffset(
8)]
        
public int right;
        [FieldOffset(
12)]
        
public int bottom;
    }

    
class LibWrapper
    {
        [DllImport(
"user32.dll", CallingConvention = CallingConvention.StdCall)]
        
public static extern bool PtInRect(ref Rect1 r, Point p);

        [DllImport(
"user32.dll", CallingConvention = CallingConvention.StdCall)]
        
public static extern bool PtInRect(ref Rect2 r, Point p);
    }

    
class TestApplication
    {
        
public static void Main()
        {
            
try
            {
                
bool PointInRect;

                Point myPoint 
= new Point();
                myPoint.x 
= 50;
                myPoint.y 
= 50;

                Rect1 rect1 
= new Rect1();
                rect1.left 
= 10;
                rect1.right 
= 100;
                rect1.top 
= 10;
                rect1.bottom 
= 100;

                PointInRect 
= LibWrapper.PtInRect(ref rect1, myPoint);
                
if (PointInRect == true)
                    Console.WriteLine(
"Point lies within the Rect");
                
else
                    Console.WriteLine(
"Point did not lies within the Rect");

                Rect2 rect2 
= new Rect2();
                rect2.left 
= 10;
                rect2.right 
= 100;
                rect2.top 
= 10;
                rect2.bottom 
= 100;

                PointInRect 
= LibWrapper.PtInRect(ref rect2, myPoint);
                
if (PointInRect == true)
                    Console.WriteLine(
"Point lies within the Rect");
                
else
                    Console.WriteLine(
"Point did not lies within the Rect");
            }
            
catch (Exception e)
            {
                Console.WriteLine(
"Exception : " + e.Message);
            }
        }
    }
}

复制代码
posted on   MainTao  阅读(2221)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示