返回顶部
首页 > 资讯 > 精选 >C#指针内存控制Marshal内存数据存储原理是什么
  • 651
分享到

C#指针内存控制Marshal内存数据存储原理是什么

2023-07-05 06:07:56 651人浏览 八月长安
摘要

本篇内容介绍了“C#指针内存控制Marshal内存数据存储原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!了解内存的原理内存是由 K

本篇内容介绍了“C#指针内存控制Marshal内存数据存储原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

了解内存的原理

内存是由 Key 和 Value 组成,Key 是内存地址、Value 是存储的数据;

Key:是一个32位长度的二进制数;(64位的程序则是64位长度的二进制)

  • > 32位最大值为二进制 ‭0111 1111 1111 1111 1111 1111 1111 1111‬

  • 或十六进制 0x7FFF FFFF,或十进制 2 147 483 647 (2GB) (int.MaxValue);

  • > 在C#程序中由 IntPtr 类型进行存储,常以十六进制数进行交互;

Value:则是一个8位长度的二进制数;(所以说计算机只能存储 0 和 1 就是这原因)

  • > 最大值为二进制 1111 1111‬,或十六进制 0xFF,或十进制 255;

  • > 也就是 1byte 的数据,所以说计算机最小存储单位为 byte 也正是如此;

内存组成结构如下:

  • >  二进制:Key (0111 1111 1111 1111 1111 1111 1111 1111‬) = Value (1111 1111)

  • >  十六进制:Key (0x7FFF FFFF) = Value (0xFF)

  • >  十进制:Key (2 147 483 647) = Value (255)

  • >  程序:Key (IntPtr) = Value (byte)

了解指针的原理

指针是用于指向一个值类型数据,非想象中的面向过程逻辑、认为第一个读取后会自动指向下一个,哈哈;

如 int 类型的指针,就是将指定内存地址中的数据转换成 int 数据;

由于 int 类型长度为32位(4byte),所以指针读取数据时会自动取连续4byte的数据来转换成 int;

  • > 如一个 int 类型值为 123456,假设他的内存地址为 IntPtr(0x014245E0),那么他所占用的内存块则为以下:

  • 第1byte:IntPtr(0x014245E0) = byte(0x40)

  • 第2byte:IntPtr(0x014245E1) = byte(0xE2)

  • 第3byte:IntPtr(0x014245E2) = byte(0x01)

  • 第4byte:IntPtr(0x014245E3) = byte(0x00)

  • 组成结构为:IntPtr(0x014245E0) = byte[] { 0x40, 0xE2, 0x01, 0x00 }

  • > 那么下一个对象则就从 IntPtr(0x014245E4) 开始,如:IntPtr(0x014245E4) = byte[] { 0x00, 0x00, 0x00, 0x00 };

OK,说完原理得开始说代码了,来个华丽的分割线;

再声明一下: 

  • 由于 C# 程序中默认是不允许使用不安全代码,如内存控制、指针等操作;

  • 所以关于非安全操作的代码需要写在 unsafe 语句块中;

  • 另外还需要设置允许使用不安全代码,如:解决方案 > 选择项目 > 右键 > 属性 > 生成 > [√] 允许不安全代码;

1、通过指针修改 值类型 的变量数据

int val = 10; unsafe{    int* p = &val;  //&val用于获取val变量的内存地址,*p为int类型指针、用于间接访问val变量     *p *= *p;       //通过指针修改变量值(执行此操作后 val 变量值将会变成 100)}

2、通过指针修改 引用类型 的变量数据

string val = "ABC"; unsafe{    fixed (char* p = val)   //fixed用于禁止垃圾回收器重定向可移动的变量,可理解为定引用类型对象    {        *p = 'D';           //通过指针修改变量值(执行此操作后 val 变量值将会变成 "DBC")        p[2] = 'E';         //通过指针修改变量值(执行此操作后 val 变量值将会变成 "DBE")        int* p2 = (int*)p;  //将char类型的指针转换成int类型的指针    }}

3、通过指针修改 数组对象 的成员数据

double[] array = { 0.1, 1.5, 2.3 }; unsafe{    fixed (double* p = &array[2])    {        *p = 0.2;           //通过指针修改变量值(执行此操作后 array 变量值将会变成{ 0.1, 1.5, 0.2 })    }}

4、通过指针修改 类对象 的字段数据

User val = new User() { age = 25 }; unsafe{    fixed (int* p = &val.age)   //fixed用于禁止垃圾回收器重定向可移动的变量,可理解为锁定引用类型对象    {        *p = *p + 1;            //通过指针修改变量值(执行此操作后 val.age 变量值将会变成 26)    }} 

5、通过IntPtr自定义内存地址修改 值类型 数据

char val = 'A'; unsafe{    int valAdd = (int)&val;             //获取val变量的内存地址,并将地址转换成十进制数     //IntPtr address = (IntPtr)123;     //选择一个内存地址(可以是任何一个变量的内存地址)    IntPtr address = (IntPtr)valAdd;    //选择一个内存地址(暂使用val变量的内存地址做测试)                                        byte* p = (byte*)address;           //将指定的内存地址转换成byte类型的指针(如果指定的内存地址不可操的话、那操作时则会报异常“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”)    byte* p2 = (byte*)2147483647;       //还可通过十进制的方式选择内存地址    byte* p3 = (byte*)0x7fffffff;       //还可通过十六进制的方式选择内存地址                                            *p = (byte)'B';                     //通过指针修改变量值(执行此操作后 val 变量值将会变成 'B')}

6、void* 一个任意类型的指针

int valInt = 10;        //定义一个int类型的测试valchar valChar = 'A';     //定义一个char类型的测试val int* pInt = &valInt;    //定义一个int*类型的指针char* pChar = &valChar; //定义一个char*类型的指针 void* p1 = pInt;        //void*可以用于存储任意类型的指针void* p2 = pChar;       //void*可以用于存储任意类型的指针 pInt = (int*)p2;        //将void*指针转换成int*类型的指针 (#需要注意一点:因为都是byte数据、所以不会报转换失败异常)pChar = (char*)p1;      //将void*指针转换成char*类型的指针(#需要注意一点:因为都是byte数据、所以不会报转换失败异常)

7、stackalloc 申请内存空间

unsafe{    int* intBlock = stackalloc int[100];    char* charBlock = stackalloc char[100];}

8、Marshal 操作内存数据

using System.Runtime.InteropServices; //int length = 1024;                //定义需要申请的内存块大小(1KB)int length = 1024 * 1024 * 1024;    //定义需要申请的内存块大小(1GB)IntPtr address = Marshal.AllocHGlobal(length);                //从非托管内存中申请内存空间,并返会该内存块的地址 (单位:字节)                                                              //相当于byte[length]                                                              //注意:申请内存空间不会立即在任务管理器中显示内存占用情况try{    #region Marshal - 写入    {        Marshal.WriteByte(address, 111);                      //修改第一个byte中的数据        Marshal.WriteByte(address, 0, 111);                   //修改第一个byte中的数据        Marshal.WriteByte(address, 1, 222);                   //修改第二个byte中的数据        Marshal.WriteByte(address, length - 1, 255);          //修改最后一个byte中的数据 (#此处需要注意,如果定义的偏移量超出则会误修改其他变量的数据)    }    #endregion     #region Marshal - 读取    {        int offset = length - 1;    //定义读取最后一个byte的内容         byte buffer0 = Marshal.ReadByte(address);             //读取第一个byte中的数据        byte buffer1 = Marshal.ReadByte(address, 0);          //读取第一个byte中的数据        byte buffer2 = Marshal.ReadByte(address, 1);          //读取第二个byte中的数据        byte buffer3 = Marshal.ReadByte(address, length - 1); //读取最后一个byte中的数据    }    #endregion     #region Marshal - 数组数据写入到目标内存块中    {        //source可以是byte[]、也可以是int[]、char[]...        byte[] source = new byte[] { 1, 2, 3 };         //将source变量的数组数据拷贝到address内存块中        Marshal.Copy(source: source,            startIndex: 0,          //从source的第一个item开始            length: 3,              //选择source的3个item            destination: address);  //选择存储的目标 (会写到address内存块的开头处)    }    #endregion     #region Marshal - 内存块数据读取到目标数组中    {        //dest可以是byte[]、也可以是int[]、char[]...        byte[] dest = new byte[5];         Marshal.Copy(source: address,            destination: dest,      //#注意:目标数组不能为空、且需要有足够的空间可接收数据            startIndex: 1,          //从dest数组的第二个item开始            length: 3);             //将address内存块的前3个item写入到dest数组中    }    #endregion     unsafe    {        int[] array = new int[5] { 1, 2, 3, 4, 5 };         int* p = (int*)Marshal.UnsafeAddrOfPinnedArrayElement(array, 1);    //获取数组第二个item的内存地址、并转换成int类型的指针        char* p2 = (char*)Marshal.UnsafeAddrOfPinnedArrayElement(array, 1); //获取数组第二个item的内存地址、并转换成char类型的指针    }}finally{    Marshal.FreeHGlobal(address);   //释放非托管内存中分配出的内存 (释放后可立即腾出空间给系统复用)}

“C#指针内存控制Marshal内存数据存储原理是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: C#指针内存控制Marshal内存数据存储原理是什么

本文链接: https://www.lsjlt.com/news/350069.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C#指针内存控制Marshal内存数据存储原理是什么
    本篇内容介绍了“C#指针内存控制Marshal内存数据存储原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!了解内存的原理内存是由 K...
    99+
    2023-07-05
  • C#指针内存控制Marshal内存数据存储原理分析
    目录了解内存的原理了解指针的原理1、通过指针修改 值类型 的变量数据2、通过指针修改 引用类型 的变量数据3、通过指针修改 数组对象 的成员数据4、通过指针修改 类对象 的字段数据5...
    99+
    2023-02-26
    C#指针 指针Marshal C#内存数据存储原理
  • C++内存管理原理是什么
    这篇文章主要讲解了“C++内存管理原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++内存管理原理是什么”吧!1.C/C++中程序内存分布C/C++中程序内存区域大致划分为:内核空...
    99+
    2023-06-25
  • golang函数指针内存管理
    在 go 语言中,函数指针在分配时使用 make 函数,并在不再需要时通过将其设置为 nil 来释放,以防止内存泄漏。具体步骤为:使用 make 函数分配函数指针。垃圾收集器自动释放未引...
    99+
    2024-04-23
    golang 指针
  • C#操作内存的指针怎么理解
    本篇内容介绍了“C#操作内存的指针怎么理解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!C#操作内存通过指针之托管代码一般来说你在写任意一个...
    99+
    2023-06-17
  • C++ 内存管理:理解指针和引用
    c++++内存管理依赖指针和引用来高效管理内存。指针存储其他变量的地址,允许间接访问和修改值;引用直接指向对象,不能重新分配。实战案例包括使用指针遍历数组和使用引用交换变量。最佳实践包括...
    99+
    2024-05-03
    c++ 内存管理
  • C语言数据在内存中的存储
    这篇文章主要介绍了C语言数据在内存中的存储,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。数据类型详细介绍在前面C语言基础概览中,已经提到过了基本的C语言内置类型,但C语言的数...
    99+
    2023-06-15
  • 理解 C++ 函数指针的内存管理:避免指针陷阱
    在 c++++ 中使用函数指针时,必须谨慎考虑内存管理以避免陷阱。这些陷阱包括悬浮指针(指向超出其范围的函数)和野指针(从未初始化或设置为 nullptr 的函数指针)。为了避免这些陷阱...
    99+
    2024-04-29
    c++ 函数指针 typedef
  • C语言中数据在内存中是怎么存储的
    本篇文章为大家展示了C语言中数据在内存中是怎么存储的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。数据类型常见的数据类型常见的数据类型字节char字符数据类型1short短整型2int整形4long...
    99+
    2023-06-22
  • Mysql存储引擎与数据存储的原理是什么
    Mysql存储引擎与数据存储的原理是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。前言作为一名开发人员,在日常的工作中会难以避免地接触到数...
    99+
    2024-04-02
  • C++ 内存管理如何预防内存泄漏和野指针问题?
    对于 c++++ 中的内存管理,有两种常见错误:内存泄漏和野指针。解决这些问题的方法包括:使用智能指针(如 std::unique_ptr 和 std::shared_ptr)自动释放不...
    99+
    2024-05-24
    内存管理 野指针 c++ 作用域
  • C语言数据在内存中是怎样存储的
    这篇文章主要介绍“C语言数据在内存中是怎样存储的”,在日常操作中,相信很多人在C语言数据在内存中是怎样存储的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言数据在内存中是怎样存储的”的疑惑有所帮助!接下来...
    99+
    2023-06-08
  • redis缓存存储Session原理机制是什么
    这篇文章主要讲解了“redis缓存存储Session原理机制是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“redis缓存存储Session原理机制是什么”吧!基于 Redis 存储 S...
    99+
    2023-06-25
  • C/C++指针与内存管理图文详解
    目录一.指针二.数组总结指针和内存管理始终是C/C++比较容易模糊的知识点,但在C/C++编程中又绕不开的地方,特别在下位机上,会频繁的与指针打交道,如果概念模糊,一不小心就会写出冗...
    99+
    2024-04-02
  • C语言进制转换、整数和小数内存存储模型是什么
    本篇内容主要讲解“C语言进制转换、整数和小数内存存储模型是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言进制转换、整数和小数内存存储模型是什么”吧! 什么是进制进制也就是进位...
    99+
    2023-06-08
  • Python内存管理机制的原理是什么
    今天就跟大家聊聊有关Python内存管理机制的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。小块空间的内存池在Python中,许多时候申请的内存都是小块的内存,这些小块内存...
    99+
    2023-06-17
  • C语言中数据在内存如何存储
    目录数据类型类型的基本归类整形有符号数和无符号数是否char 等于signed char呢?浮点型构造类型(自定义类型)指针类型空类型整形在内存中的存储原码,反码,补码正整数负整数大...
    99+
    2024-04-02
  • C++浅析数据在内存中如何存储
    目录一、数据类型二、原码反码补码三、大小端整型提升一、数据类型 数据类型有7种:    char         ...
    99+
    2022-11-13
    C++数据存储 C++数据在内存中存储
  • prometheus存储数据的原理是什么
    Prometheus是一个开源的监控系统,用于收集、存储和查询时间序列数据。它的存储数据的原理是基于一种称为TSDB(Time Se...
    99+
    2024-04-09
    prometheus
  • C语言中数据是如何存储在内存中的
    目录前言‍数据类型介绍‍整形数据在内存中存储‍浮点型数据在内存存储前言 在计算机内存中,数据的存储方式都是以0和1的形式存储,也就是二进制的形式,数据是如何向...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作