IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C#的fixed关键字获取指针地址以及固定内存 -> 正文阅读

[C++知识库]C#的fixed关键字获取指针地址以及固定内存

我在查看BitConverter类的源代码时,突然发现大量使用 fixed关键字.

Reference Source

如下代码,将Int16转化为两个字节【C#中,是低字节在前的】

public static readonly bool IsLittleEndian = true;
// Converts a short into an array of bytes with length
        // two.
        [System.Security.SecuritySafeCritical]  // auto-generated
        public unsafe static byte[] GetBytes(short value)
        {
            Contract.Ensures(Contract.Result<byte[]>() != null);
            Contract.Ensures(Contract.Result<byte[]>().Length == 2);
 
            byte[] bytes = new byte[2];
            fixed(byte* b = bytes)
                *((short*)b) = value;
            return bytes;
        }

将4个字节转化为一个Int32数

// Converts an array of bytes into an int.  
        [System.Security.SecuritySafeCritical]  // auto-generated
        public static unsafe int ToInt32 (byte[] value, int startIndex) {
            if( value == null)  {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
            }
        
            if ((uint) startIndex >= value.Length) {
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
            }
        
            if (startIndex > value.Length -4) {
                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
            }
            Contract.EndContractBlock();
 
            fixed( byte * pbyte = &value[startIndex]) {
                if( startIndex % 4 == 0) { // data is aligned 
                    return *((int *) pbyte);
                }
                else {
                    if( IsLittleEndian) { 
                        return (*pbyte) | (*(pbyte + 1) << 8)  | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24);
                    }
                    else {
                        return (*pbyte << 24) | (*(pbyte + 1) << 16)  | (*(pbyte + 2) << 8) | (*(pbyte + 3));                        
                    }
                }
            }
        }

下面对fixed关键字进行说明 以及使用场景

参考微软官方文档:

fixed 语句 -
C# 参考 | Microsoft Docs

fixed 语句可防止垃圾回收器重新定位可移动的变量。 fixed 语句仅允许存在于fixed上下文中。 还可以使用 fixed 关键字创建fixed。一般fixed关键字都用在unsafe【不安全】的环境中

fixed 语句将为托管变量设置一个指针,并在该语句的执行过程中“单边锁定”该变量。 仅可在 fixed 上下文中使用指向可移动托管变量的指针。 如果没有 fixed 上下文,垃圾回收可能会不可预测地重定位变量。 C# 编译器只允许将指针分配给 fixed 语句中的托管变量。

使用fixed关键字 可以提升运算的性能,

? 不能使用 fixed 语句来获取已固定的表达式的地址,因此fixed不能获取结构struct的地址

可以通过使用一个数组、字符串、固定大小的缓冲区或变量的地址来初始化指针。

执行该fixed语句中的代码之后,任何固定的变量都将被解锁并受垃圾回收的约束。 因此,请勿指向?fixed?语句之外的那些变量。 在?fixed?语句中声明的变量的作用域为该语句,使此操作更容易:

在?fixed?语句中初始化的指针为只读变量。 如果想要修改指针值,必须声明第二个指针变量,并修改它。 不能修改在?fixed?语句中声明的变量:

可以在堆栈上分配内存,在这种情况下,内存不受垃圾回收的约束,因此不需要固定。 为此,请使用?表达式。

使用VisualStudio2022新建控制台应用程序FixedDemo,选择.net 5.0

右键FixedDemo项目,选择属性,勾选“允许使用unsafe关键字编译的代码”。

?源程序如下:

using System;

namespace FixedDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"测试fixed关键字,将数组的一部分转化为Span");
            FixedSpanExample();
            Console.WriteLine($"测试使用指针修改存储的值");
            ModifyFixedStorage();
            Console.WriteLine();
        }

        /// <summary>
        /// fixed关键字示例
        /// </summary>
        unsafe private static void FixedSpanExample()
        {
            int[] PascalsTriangle = {
                  1,
                1,  1,
              1,  2,  1,
            1,  3,  3,  1,
          1,  4,  6,  4,  1,
        1,  5,  10, 10, 5,  1
            };

            Span<int> RowFive = new Span<int>(PascalsTriangle, 10, 5);

            fixed (int* ptrToRow = RowFive)
            {
                // 计算数字之和 1,4,6,4,1
                int sum = 0;
                for (int i = 0; i < RowFive.Length; i++)
                {
                    sum += *(ptrToRow + i);
                }
                Console.WriteLine(sum);
            }
        }

        /// <summary>
        /// 使用fixed指针修改内存的值,不能使用fixed关键字获取结构的地址
        /// </summary>
        unsafe private static void ModifyFixedStorage()
        {
            // Variable pt is a managed variable, subject to garbage collection.
            Coordinate coordinate = new Coordinate()
            {
                X = 100,
                Y = 200
            };
            Console.WriteLine($"初始值:X={coordinate.X},Y={coordinate.Y}");

            // Using fixed allows the address of pt members to be taken,
            // and "pins" pt so that it is not relocated.

            fixed (int* p = &coordinate.X, q = &coordinate.Y)
            {
                *p = 12345;
                *q = 67890;
            }
            Console.WriteLine($"修改后的值:X={coordinate.X},Y={coordinate.Y}");
        }
    }

    /// <summary>
    /// 坐标,fixed关键字不能获取已固定的表达式的地址
    /// 因此fixed不能获取结构struct的地址
    /// </summary>
    class Coordinate 
    {
        public int X;
        public int Y;
        public int Z;
    }
}

程序运行如图:

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 15:59:31  更:2022-04-06 16:02:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:35:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码