惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tenable Blog
Last Week in AI
Last Week in AI
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
H
Help Net Security
F
Fortinet All Blogs
MyScale Blog
MyScale Blog
宝玉的分享
宝玉的分享
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 司徒正美
量子位
N
Netflix TechBlog - Medium
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
Recorded Future
Recorded Future
博客园 - 三生石上(FineUI控件)
Vercel News
Vercel News
aimingoo的专栏
aimingoo的专栏
I
InfoQ
Microsoft Security Blog
Microsoft Security Blog
Scott Helme
Scott Helme
The Last Watchdog
The Last Watchdog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
IT之家
IT之家
AI
AI
WordPress大学
WordPress大学
Security Archives - TechRepublic
Security Archives - TechRepublic
Google Online Security Blog
Google Online Security Blog
U
Unit 42
V2EX - 技术
V2EX - 技术
MongoDB | Blog
MongoDB | Blog
Schneier on Security
Schneier on Security
博客园 - Franky
H
Heimdal Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Jina AI
Jina AI
W
WeLiveSecurity
P
Privacy & Cybersecurity Law Blog
Cloudbric
Cloudbric
B
Blog RSS Feed
N
News | PayPal Newsroom
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
I
Intezer
Hacker News - Newest:
Hacker News - Newest: "LLM"
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园_首页
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
雷峰网
雷峰网

博客园 - MainIsUsed

svg札记 rabbitmq 小记 nfc相关 MI卡UID oracle9i导入导出命令 (转)C++中指针和引用的区别 .net下的office开发(visio对象) 关于DataTable的GetChanges()方法 Oracle中UTL_FILE包的UTL_FILE.FOPEN用法 c# 获取串口设备的输入(unsigned char *和 char*) URL字符串编码 笔记HTML - MainIsUsed - 博客园 .net导出为powerpoint的一些参考代码 关于ClickOnce 发布过程中的错误:要求高版本的CAPICOM.dll Oracle EXTRACT()函数与to_char() 函数 c#接口使用方法 - MainIsUsed - 博客园 在 WinForm 中完整支持在多级目录中保存的 ASP.NET (转) - MainIsUsed (转)实现基于事件通知的.Net套接字 (转)什么是套接字(Socket)?
【转】C#中的非安全编程(key:unsafe,fixed)
MainIsUsed · 2009-06-02 · via 博客园 - MainIsUsed

本文将讨论如何在C#中使用指针。

介绍
  这是C/C++程序迷们经常谈论的一个话题,同时也是一个复杂的、难以理解的话题-指针!每次谈到C#,大多数我遇到的人都持这样的观点-C#中没有指针的概念。而实际上,它已经被废除了,取而代之的是C#中的非安全编程-如何在程序中使用指针。不同于其字面意思的是,使用指针编程并没有什么不安全的。
  它如此受关注的根本原因是,非安全编程不同于习惯的.NET开发规范,而需要编程人员进行明确定本地环境设置(仅适用于本地执行)。本文我将从区别两个最容易被疑惑的概念-非安全代码与非受控代码开始讨论非安全编程这个主题。接下来我们将讨论如何编写非安全代码,亦即如何在C#中使用指针。

非安全还是非受控?

受控代码是指在CLR管理下执行的代码。CLR负责了许多幕后的工作:

  • 管理对象的内存
  • 进行类型验证
  • 垃圾回收

  说了这些,实际就是要将用户从上述的这些工作中解脱出来了,专心于业务实现。用户不再需要直接手工地进行内存操作,因为这些工作已由CLR完成了。
  另一方面,非受控代码就是在CLR上下文外执行的代码了。最好的例子就是我们平时使用的Win32 DLL,比如kernel32.dll,user32.dll以及安装上我们系统上的各种COM组件。如何为它们分配内存、如何释放这些内存、如何实现类型验证?这些工作都需要它们自己来完成。一个典型的C++程序中分配一个字符指针的语句也是非受控代码的另一类例子,因为作为一名编程者,你要负责:

  • 调用内存分配函数
  • 确保类型转换的结果正确
  • 确保指针在使用完毕后其内存被释放

如果你留心上面的解释,所有这些工作都是由CLR来完成以减轻编程者的负担。

非安全代码是介于受控与非受控代码间的一种代码类型

  非安全代码仍然象受控代码一样是在CLR的管理下执行的,但在同时它又象非受控代码一样允许你通过指针直接访问内存。因此你获得了两者的优点。如果你正在编写写一个.NET应用程序,但同时又希望可以广泛使用Win32 DLL中的各种函数-需要使用指针的,那么此时非安全代码就是你的救星了。
  我们已经明确了两者的区别后,就开始编写实际的代码,毫无疑问,这才是最精彩的部分,你还在想什么呢?

深入非安全代码
  编写非安全代码需要使用特殊的关键字unsafefixed。如果你还记得的话,有三种指针操作符:

  • *
  • &
  • ->

  任何使用了上述任一指针操作符的语句、语句块或者函数都应用unsafe关键字标记为非安全代码,就象这样:

public unsafe void Triple(int *pInt)
{
  *pInt=(*pInt)*3;
}

  上面这个函数只是将传入的参数的值扩大了两倍。但是请注意,传入的是这个参数的指针!因为这个函数使用了"*"操作符直接进行内存操作,因此被标记为 unsafe
  但是这里还是有一个问题。回想一下上面的讨论,非安全代码也是在CLR管理下的受控代码,CLR可以自由地将对象移入内存中。于是一个似是而非的原因可能导致内存泄漏。这样做的结果是,对于编程者可能在自觉不自觉中使这个变量的指针指向内存的其他地方。
  因此假设*pInt指向的地址是1001,而CLR的内存重定位过程将会引发内存泄漏。pInt之前指向1001,在重定位后其指向的数据可能被存储在地址2003处。于是大祸临头了!pInt指向的1001处存储的数据在经过重定位过程后无效了。这也许就是.NET很少提及指针的使用的原因吧,你认为呢?

固定指针
  在语句块前输入关键字fixed,将会告诉CLR块内的对象不能重定位,这样CLR就不会重定位指针指向的数据存储位置。因此在C#中使用指针时,使用关键字fixed将能阻止程序运行时无效指针的产生。让我们看看它是如何工作的:

using System;
class CData
{
    public int x;
}

class CProgram
{
    unsafe static void SetVal(int *pInt)
    {
        *pInt=1979;
    }
    
    public unsafe static void Main()
    {
        CData d = new CData();
        
        Console.WriteLine("Previous value: {0}", d.x);
        
        fixed(int *p=&d.x)
        {
            SetVal(p);
        }
        
        Console.WriteLine("New value: {0}", d.x);
    }
}

  我们在这段代码里通过一个fixed块,将CData对象数据成员(域)x的地址赋给了一个整数型指针p。当fixed块中的语句被执行时,这个指针p将一直指向原来的那块内存区域,因为CLR已被指示暂时冻结这个变量直到该fixed块执行完毕。一旦fixed块执行完毕,这个对象就又能被CLR重新定位了。
  以上就是C#中使用指针编程的介绍,关键是要说明语句块是 unsafe 并 fixed 的。希望能因此提高你对C#中指针使用的知识!