1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8.  
  9. namespace ConsoleApplication1
  10. {
  11. class CTile
  12. {
  13. public CTileData _dat;
  14. public int x;
  15. }
  16.  
  17. //结构体可能分配在堆上,也可能分配在栈上
  18.  
  19. //1,结构体中无引用类型,则:
  20. //a:若该结构体类型的变量X是类的内部成员,由于类是引用类型,则X分配在堆上
  21. //b:若非a的情况,则结构体分配在栈上
  22. unsafe struct CTileData//为了避开C#数组,因为它是一个引用类型。
  23. {
  24. public int var1;
  25. public float var2;
  26. public fixed sbyte name[]; //使用C++风格的定长数组,避免C#风格的引用数组
  27. public float var3;
  28. }
  29.  
  30. //2,结构体中有引用类型,则该结构体类型的变量分配在堆上
  31. struct CTileData2
  32. {
  33. public int var1;
  34. public float var2;
  35. public string name;//有引用类型,结构体无论如何都分配在堆上了
  36. public float var3;
  37. }
  38.  
  39. unsafe class Program
  40. {
  41. [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
  42. static extern void MemCopy(void* dest, void* src, int count);
  43.  
  44. static void Main(string[] args)
  45. {
  46. unsafe
  47. {
  48.  
  49. var tile = new CTile();
  50. var dat = new CTileData();
  51.  
  52. //栈上的结构体,可以直接取地址,堆上的则不行,因为堆上对象的地址是不定的(原因是内存管理)
  53. //同理,堆上的任何对象都不可直接取地址,必须使用fixed才行
  54. CTileData* ptd = &dat;
  55.  
  56. var ms = new MemoryStream();
  57. var binWr = new BinaryWriter(ms, Encoding.ASCII);
  58. binWr.Write();
  59. binWr.Write(3.2f);
  60. binWr.Write("hello");//先写入1字节长度(也就是说字符串长度最大256???),然后写入hello
  61. binWr.Write(109.9f);
  62.  
  63. var bts = ms.GetBuffer();
  64.  
  65. fixed (void* pbts = bts)//堆对象,必须使用fixed语法才能取地址
  66. {
  67. var sz = sizeof(CTileData);
  68. MemCopy(ptd, pbts, sz);
  69.  
  70. fixed (void* pt = &tile._dat)//堆上的结构体(堆对象),必须使用fixed语法才能取地址
  71. {
  72. MemCopy(pt, pbts, sz);
  73. }
  74.  
  75. }
  76.  
  77. var v1 = ptd->var1; //
  78. var v2 = ptd->var2; //3.2
  79. var strlen = *(ptd->name); //取一字节,字符串长度 5
  80. var straddr = ptd->name + ; //跳过一字节,到达字符串起始地址
  81. string name = new string(straddr, , strlen); //hello
  82. var v3 = ptd->var3; //这里数据不对,原因????
  83.  
  84. //结论:C#真不适合做内存操作,若使用marshal,虽然方便了一些,但要经过一次内存申请和一次内存释放,一次转换到C#结构的过程,很蹩脚
  85. }
  86. }
  87. }
  88. }

C# unsafe模式内存操作深入探索的更多相关文章

  1. Linux操作系统基础(四)保护模式内存管理(2)【转】

    转自:http://blog.csdn.net/rosetta/article/details/8570681 Linux操作系统基础(四)保护模式内存管理(2) 转载请注明出处:http://blo ...

  2. Java API —— IO流(数据操作流 & 内存操作流 & 打印流 & 标准输入输出流 & 随机访问流 & 合并流 & 序列化流 & Properties & NIO)

    1.操作基本数据类型的流     1) 操作基本数据类型 · DataInputStream:数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型.应用程序可以使用数据输出 ...

  3. 【嵌入式开发】裸机引导操作系统和ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 )

    [嵌入式开发]ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 )     一. 内存 ...

  4. LabVIEW之生产者/消费者模式--队列操作 彭会锋

    LabVIEW之生产者/消费者模式--队列操作 彭会锋 本文章主要是对学习LabVIEW之生产者/消费者模式的学习笔记,其中涉及到同步控制技术-队列.事件.状态机.生产者-消费者模式,这几种技术在在本 ...

  5. java 21-11 数据输入、输出流和内存操作流

    IO数据流: 可以读写基本数据类型的数据 数据输入流:DataInputStream DataInputStream(InputStream in)   数据输出流:DataOutputStream ...

  6. 【转】《深入理解计算机系统》C程序中常见的内存操作有关的典型编程错误

    原文地址:http://blog.csdn.net/slvher/article/details/9150597 对C/C++程序员来说,内存管理是个不小的挑战,绝对值得慎之又慎,否则让由上万行代码构 ...

  7. c++ void,内存操作函数

    void的含义 void的字面意思是“无类型”, void * 则为“无类型指针”, void * 可以指向任何类型的数据 void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变 ...

  8. java基础知识回顾之javaIO类--内存操作流ByteArrayInputStream和ByteArrayOutputSteam(操作字节数组)

    直接看代码: package cn.itcast.io.p6.bytestream; import java.io.ByteArrayInputStream; import java.io.ByteA ...

  9. 【C++基础】内存操作 getMemory改错

    内存操作的考察点:①指针 ②变量生存期及作用范围 ③动态内存申请和释放 笔试题************************************************************* ...

随机推荐

  1. Codeforces 633H Fibonacci-ish II【线段树】

    LINK 题目大意 给你一个序列a,Q次询问,每次询问\([l,r]\) 把\([l,r]\)的数排序去重,得到序列b,f是斐波那契数列 求\(\sum_{b=1}^{len} b_if_i\) 思路 ...

  2. 《DSP using MATLAB》示例Example 8.9

  3. 《DSP using MATLAB》示例Example6.2

    2017年了,阳历新年都11号了,已从外地回到家乡,依然苦逼的生活…… 接着写读书(Digital Signal Processing using MATLAB)笔记吧 代码: b = [1 -3 1 ...

  4. scrapy 伪装代理和fake_userAgent的使用

    伪装浏览器代理 在爬取网页是有些服务器对请求过滤的不是很高可以不用ip来伪装请求直接将自己的浏览器信息给伪装也是可以的. 第一中方法: 1.在setting.py文件中加入以下内容,这是一些浏览器的头 ...

  5. 一张elixir生产环境部署的图

  6. 10.Python运行Scrapy时出现错误: ModuleNotFoundError: No module named 'win32api'

    1.在命令行输入:scrapy crawl demo(demo为爬虫标识,是唯一的) 2.报错信息如下所示: 3.解决方法:https://github.com/mhammond/pywin32/re ...

  7. Hibernate Cannot release connection 了,有办法解决!

      问题:    系统采用Spring MVC 2.5 + Spring 2.5 + Hibernate 3.2架构,其中数据源连接池采用的是Apache commons DBCP.问题是这样的,系统 ...

  8. 执行npm install报错:npm ERR! code EINTEGRITY

    命令行执行npm install报错如下: D:\frontend\viewsdev>npm install npm ERR! code EINTEGRITY npm ERR! sha512-8 ...

  9. C++直接初始化和复制初始化2

    现在正式对C++中对象建立和初始化做一个总结. (1)复制初始化的基本原理 我们知道,对象在内存中的直接表象是在内存中占有一个一定大小的空间.分配空间是建立对象的第一步.但是刚刚分配的空间就像一个没有 ...

  10. GTID 跳过脚本

    跳过单个error STOP SLAVE; SET gtid_next = '3b977b7e-ed28-11e7-a8ff-b4969113b678:138609841'; BEGIN;COMMIT ...