博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# unsafe模式内存操作深入探索
阅读量:4562 次
发布时间:2019-06-08

本文共 2616 字,大约阅读时间需要 8 分钟。

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Runtime.InteropServices;using System.Text;using System.Threading.Tasks;namespace ConsoleApplication1{    class CTile    {        public CTileData _dat;        public int x;    }    //结构体可能分配在堆上,也可能分配在栈上    //1,结构体中无引用类型,则:    //a:若该结构体类型的变量X是类的内部成员,由于类是引用类型,则X分配在堆上    //b:若非a的情况,则结构体分配在栈上    unsafe struct CTileData//为了避开C#数组,因为它是一个引用类型。    {        public int var1;        public float var2;        public fixed sbyte name[6]; //使用C++风格的定长数组,避免C#风格的引用数组        public float var3;    }        //2,结构体中有引用类型,则该结构体类型的变量分配在堆上    struct CTileData2    {        public int var1;        public float var2;        public string name;//有引用类型,结构体无论如何都分配在堆上了        public float var3;    }    unsafe class Program    {        [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]        static extern void MemCopy(void* dest, void* src, int count);        static void Main(string[] args)        {            unsafe            {                var tile = new CTile();                var dat = new CTileData();                //栈上的结构体,可以直接取地址,堆上的则不行,因为堆上对象的地址是不定的(原因是内存管理)                //同理,堆上的任何对象都不可直接取地址,必须使用fixed才行                CTileData* ptd = &dat;                 var ms = new MemoryStream();                var binWr = new BinaryWriter(ms, Encoding.ASCII);                binWr.Write(10);                binWr.Write(3.2f);                binWr.Write("hello");//先写入1字节长度(也就是说字符串长度最大256???),然后写入hello                binWr.Write(109.9f);                var bts = ms.GetBuffer();                fixed (void* pbts = bts)//堆对象,必须使用fixed语法才能取地址                {                    var sz = sizeof(CTileData);                    MemCopy(ptd, pbts, sz);                    fixed (void* pt = &tile._dat)//堆上的结构体(堆对象),必须使用fixed语法才能取地址                    {                        MemCopy(pt, pbts, sz);                    }                }                var v1 = ptd->var1;                             //10                var v2 = ptd->var2;                             //3.2                var strlen = *(ptd->name);                      //取一字节,字符串长度 5                var straddr = ptd->name + 1;                    //跳过一字节,到达字符串起始地址                string name = new string(straddr, 0, strlen);   //hello                var v3 = ptd->var3;                             //这里数据不对,原因????                                //结论:C#真不适合做内存操作,若使用marshal,虽然方便了一些,但要经过一次内存申请和一次内存释放,一次转换到C#结构的过程,很蹩脚            }        }    }}

 

转载于:https://www.cnblogs.com/timeObjserver/p/8728282.html

你可能感兴趣的文章
不变模式
查看>>
20181227 新的目标
查看>>
androidtab
查看>>
php 事件驱动 消息机制 共享内存
查看>>
剑指offer 二叉树的bfs
查看>>
LeetCode Maximum Subarray
查看>>
让我们再聊聊浏览器资源加载优化
查看>>
underscore demo
查看>>
CSS hack
查看>>
每日一小练——数值自乘递归解
查看>>
qq登陆错误提示
查看>>
bzoj 1192: [HNOI2006]鬼谷子的钱袋 思维 + 二进制
查看>>
没写完,没调完,咕咕咕的代码
查看>>
Android Studio使用技巧:导出jar包
查看>>
Problem E. TeaTree - HDU - 6430 (树的启发式合并)
查看>>
Kafka序列化和反序列化与示例
查看>>
win10下VS2010中文输入法切换为英文卡死
查看>>
retinex相关代码汇总
查看>>
Cortex-M3 异常返回值EXC_RETURN
查看>>
kettle 转换字段遇到问题(couldn't get row from result set)——摘
查看>>