c#语言中代替指针,.Net(C#)中使用指针

1、在vs中使用指针,还要对项目做一些设置,需要允许不安全代码

在项目上右键属性,在点击 "生成" ,勾选允许不安代码,有些vs中那个选项可能是英文的,需要注意一下,如下图,

download?id=5bb9d83adc72d91ff8d53a07

2、C#指针的基础语法

在代码中用指针有两种方式,一种是unsafe {  },表明括中的代码是不安全的,另一种是在方法或属性上加入unsafe关键字。两种方法分别如下

1)private static IntPtr GetMemoryAddress(MethodBase mb)

{

unsafe

{

RuntimeHelpers.PrepareMethod(mb.MethodHandle);

if ((Environment.Version.Major >= 4) || ((Environment.Version.Major == 2) && (Environment.Version.MinorRevision >= 3053)))

{

return new IntPtr(((int*)mb.MethodHandle.Value.ToPointer() + 2));

}

UInt64* location = (UInt64*)(mb.MethodHandle.Value.ToPointer());

int index = (int)(((*location) >> 32) & 0xFF);

if (IntPtr.Size == 8)

{

ulong* classStart = (ulong*)mb.DeclaringType.TypeHandle.Value.ToPointer();

ulong* address = classStart + index + 10;

return new IntPtr(address);

}

else

{

uint* classStart = (uint*)mb.DeclaringType.TypeHandle.Value.ToPointer();

uint* address = classStart + index + 10;

return new IntPtr(address);

}

}

}

2)private static unsafe void MemoryPatching(MethodBase miEvaluation, MethodBase miLicensed)

{

IntPtr IntPtrEval = GetMemoryAddress(miEvaluation);

IntPtr IntPtrLicensed = GetMemoryAddress(miLicensed);

if (IntPtr.Size == 8)

*((long*)IntPtrEval.ToPointer()) = *((long*)IntPtrLicensed.ToPointer());

else

*((int*)IntPtrEval.ToPointer()) = *((int*)IntPtrLicensed.ToPointer());

}

在看一下具体怎么在C#中使用指针,怎么分配内存,和怎么释放内存。

1)要用指针操作托管堆上的值类型,需要用到 fixed关键字public unsafe class Coder

{

public int Age;

public void SetAge(int age)

{

fixed (int* p = &Age)

{

*p = age;

}

}

}

2)用指针操作栈上的值类型int* p = &maxValue;

*p = 20;

Console.WriteLine(p->ToString());

3)指针操作非托管堆上的内存,非托管的内存需要手动释放,GC就不管理了,需要手动管理。System.Runtime.InteropServices.Marshal.AllocHGlobal()//用来从非托管堆上分配内存

System.Runtime.InteropServices.Marshal.FreeHGlobal(handle)//用来释放从非托管对上分配的内存

IntPtr handle = System.Runtime.InteropServices.Marshal.AllocHGlobal(4);

Int32* p = (Int32*)handle;

*p = 20;

Console.WriteLine(p->ToString());

System.Runtime.InteropServices.Marshal.FreeHGlobal(handle);

还可以 用IDispose接口管理内存,代码如下:public unsafe class UnmanagedMemory : IDisposable

{

public int Count { get; private set; }

private byte* Handle;

private bool _disposed = false;

public UnmanagedMemory(int bytes)

{

Handle = (byte*) System.Runtime.InteropServices.Marshal.AllocHGlobal(bytes);

Count = bytes;

}

public void Dispose()

{

Dispose(true);

GC.SuppressFinalize(true);

}

protected virtual void Dispose( bool isDisposing )

{

if (_disposed) return;

if (isDisposing)

{

if (Handle != null)

{

System.Runtime.InteropServices.Marshal.FreeHGlobal((IntPtr)Handle);

}

}

_disposed = true;

}

~UnmanagedMemory()

{

Dispose( false );

}

}

使用方法:using (UnmanagedMemory memory = new UnmanagedMemory(10))

{

int* p = (int*)memory.Handle;

*p = 20;

Console.WriteLine(p->ToString());

}

4)使用stackalloc关键字在栈中分配内存,一般况下,是比堆中的内存速度快,在此情况下栈中分配的内存,方法退出内存自动释放,不用担心内存泄漏。/* 使用指针优化性能 */

//使用关键字stackalloc(指示.net运行库分配堆栈上一定内存)创建基于堆栈的高效数组

unsafe

{

/*

* stackalloc命令只分配堆栈内存而已,不会把内存初始化为任何默认值

* 1.其后紧跟要存储数据类型名(该数据类型必须是一值类型)

* 2.分配的字节数为变量个数*sizeof(数据类型)

*/

int* pInt = stackalloc int[10];

*pInt = 0;

*(pInt + 1) = 1;

pInt[2] = 5; //表达式被编译为*(pInt + 2)

pInt[50] = 100; //不报错,使用stackalloc声明一相同数组,对数组边界检查,这数组没封装任何对象

}

3、C# 指针操作的几个缺点

缺点1:只能用来操作值类型    .Net中,引用类型的内存管理全部是由GC管理的,无法取得其地址,因此,无法用指针来操作引用类型。

缺点2:泛型不支持指针类型    C# 中泛型不支持指针类型。可以考虑其它替代方案解决这个限制。

缺点3:没有函数指针    幸运的是,C# 中有delegate,delegate 支持支持指针类型,lambda 表达式也支持指针。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值