C#學習之unsafe

為了保持類型安 全,默認情況下,C# 不支持指針算法。 不過,通過使用 unsafe 關鍵字,可以定義可使用指針的不安全上下文。

?

unsafeC# 程 序中的使用場合:

1)實時應用,采用指針來提高性能;

2)引用非.net DLL提供的如C++編寫的外部函數,需要指針來傳遞該函數;

3)調試,用以檢測程序在運行過程中的內存使用狀況。

使用unsafe 的利弊:

好處:性能和靈活性提高;可以調用其他dll的函數,提高了兼容性;可以得到內存地址;

壞處:非法修改了某些變量;內存泄漏。

unsafe 與unmanaged的區別:

managed code是在CLR監管下運行的程序。以下任務由CLR來執行:管理對象內存,類型安全檢測和冗余處理。

unmanaged code也就是能由程序員直接進行內存操作的程序。

unsafe 是介于managed和unmanaged之間的橋梁,它使得managed code也能使用指針來控制和操作內存。

?

unsafe 的使用:


unsafe 可以用來修飾類、類的成員函數、類的全局變量,但不能用來修飾類成員函數內的局部變量。 編譯帶有unsafe 代碼的程序也要在 “configuration properties>build” 中把允許unsafe 代碼設為真。

但是在managed code中使用unsafe 時也要注意,正因為CLR可以操作內存對象,假如你寫了一下代碼:

???? ?public unsafe void add(int *p)
????? {
????????? *p=*p+4;
????? }

p的地址值可能會在運行過程中被CLR所修改,這通常可采用fixed來處理,使指針所指向的地址不能被改變。如下:

????? fixed(int *p=& value)
??????? {
??????????? add(p);
??????? }

?

托管代碼 (managed code):由公共語言運行庫環境(而不是直接由操作系統)執行的代碼。托管代碼應用程序可以獲得公共語言運行庫服務,例如自動
垃圾回收、運行庫類型檢查和安全支持等。這些服務幫助提供獨立于平臺和語言的、統一的托管代碼應用程序行為。

非托管代碼(Unmanaged Code):在公共語言運行庫環境的外部,由操作系統直接執行的代碼。非托管代碼必須提供自己的垃圾回收、類型檢查、安全支
持等服務;它與托管代碼不同,后者從公共語言運行庫中獲得這些服務。
Unsafe的代碼介于這兩者之間,它也是在CLR的環境中執行,但是我們可以直接操作內存。只要我們的代碼包含下面三個指針操作符之一就需要使用Unsafe
關鍵字:
* & ->

例如:

unsafe static void ChangeValue(int* pInt)
{
*pInt = 23;
}

上面的代碼由于是在CLR下托管執行,為 了減少內存碎片C#的自動垃圾回收機制會允許已經分配的內存在運行時進行位置調整,所以如果我們多次調用的話就可能
導致指針指向其他的變量。比如*pInt為 指向一個變量的地址為1001,CLR在重新內存整理分配后該變量 就存儲在地址為5001的地方。而原來1001的地方可能會
被分配其他變量,要解決這個問題我們就需要使用Fixed關鍵字。

fixed 語句禁止垃圾回收器重定位可移動的變量。fixed 語句只能出現在不安全的上下文中。Fixed 還可用于創建固定大小的緩沖區。如下面例子:

using System;
class CaryData
{
public int data;
}

class CProgram
{

unsafe static void ChangeValue(int* pInt)
{
*pInt = 23; //3為這個指針的地址賦值23
}

public unsafe static void Main()
{
CaryData cd = new CaryData();
Console.WriteLine("改變前: {0}", cd.data);

fixed (int* p = &cd.data) // 1把整形的地址賦給了指針P
{
ChangeValue(p); //2專遞指針
}
Console.WriteLine("改變后: {0}", cd.data); //4由于cd.data的和*p地址相同,所以cd.data 的輸出是23
}
}

注意要勾選項目屬性中生成標簽的允許不安全代碼。

?

T_Account ret;
unsafe
{
fixed(void* ptr = body)
{
ret = *((T_Account*)ptr); // 轉換指針為(T_Account*),再獲得指針的值也就是T_Account類型值
}
}

?

T_Account x = new T_Account();
x.ID = 12;
x.Name = "thisistest";
x.Native_Currency = "USD";
byte[] message = new byte[T_Account.Size];
unsafe
{
void* ptr = &x; //將地址賦給這個指針
fixed(void* des = message) // 值賦給了這個地址
{
MemoryUtility.CopyData(des, ptr, T_Account.Size);
}
}



(*) unsafe 和 fixed

unsafe
{??????????????
??? int[] array = new int[10];
??? for (int i = 0; i < array.Length; i++)
??? {
??????? array[i] = i;
??? }
??? fixed (int* p = array)
??? {
??????? for (int i = 0; i < array.Length; i++)
??????? {
??????????? System.Console.WriteLine(p[i]);
??????? }???????????????????
??? }??????????????
}

指針在c#中是不提倡使用的,有關指針的操作被認為是不安全的(unsafe)。因此運行這段代碼之前,先要改一個地方,否則編譯不過無法運行。
修 改方法:在右側的solution Explorer中找到你的項目,在項目圖標(綠色)上點右鍵,選最后一項properties,然后在Build標簽頁里把Allow unsafe code勾選上。之后這段代碼就可以運行了,你會看到,上面這段代碼可以像C語言那樣用指針操縱數組。但前提是必須有fixed (int* p = array),它的意思是讓p固定指向數組array,不允許改動。因 為C#的自動垃圾回收機制會允許已經分配的內存在運行時進行位置調整,如果那樣,p可能一開始指的是array,但后來array的位置被調整到別的位置 后,p指向的就不是array了。所以要加一個fixed關鍵字,把它定在那里一動不動,之后的操作才有保障。

另有兩點需要注意:

1)指針的使用必須放在unsafe的區域里;unsafe關鍵字也可作為類或方法的修飾符。

2)fixed (int* p = array)中,p的定義不能寫在別處,而且fixed關鍵字也只能在unsafe區域里使用。

(*) 略簡潔的unsafe寫法

??? class Program
??? {
??????? unsafe public static UInt16 Htons(UInt16 src)
??????? {
??????????? UInt16 dest;
??????????? // 不能照搬C的源代碼,因為有些類型長度不一樣,如char(2字節),long(8字節)
??????????? // ((char*)&dest)[0] = ((char*)&src)[1];
??????????? // ((char*)&dest)[1] = ((char*)&src)[0];
??????????? ((byte*)&dest)[0] = ((byte*)&src)[1];
??????????? ((byte*)&dest)[1] = ((byte*)&src)[0];
??????????? return dest;
??????? }

??????? public static UInt16 ConciseHtons(UInt16 src)
??????? {
??????????? UInt16 dest;
??????????? unsafe
??????????? {
??????????????? ((byte*)&dest)[0] = ((byte*)&src)[1];
??????????????? ((byte*)&dest)[1] = ((byte*)&src)[0];
??????????? }???????????
??????????? return dest;
??????? }
???????
??????? static void Main()
??????? {
??????????? UInt16 val = 1;

??????????? // 如果方法是unsafe的,則必須在unsafe block里調用
??????????? unsafe
??????????? {???????????????
??????????????? val = Htons(val);
??????????? }
??????????? Console.WriteLine(val);

??????????? // 更簡潔的寫法是把unsafe block寫在函數內部
??????????? val = ConciseHtons(val);
??????????? Console.WriteLine(val);
??????? }???????????????
??? }

(*) stackalloc

stackalloc的用處僅僅是把數組分配在棧上(默認是分配在托管堆上的)。

??? class MyClass
??? {
??????? public int val;
??? }

??? class Program
??? {???????????????
??????? static void Main()
??????? {???????????
??????????? unsafe
??????????? {???????????????
??????????????? MyClass *p = stackalloc MyClass[1]; // Error!! 如果類型要放在托管堆上則不行,如果MyClass是struct就OK了
??????????????? p->val = 1;

??????????????? int *iArray = stackalloc int[100];? // OK,在棧上創建數組, int類型本身就是放在棧上的
??????????? }???????????
??????? }???????????????
??? }

注意:指針指向的內存一定要固定。凡是C#里的引用類型(一切類型的 數組都是引用類型 )都是分配在托管堆上的,都不固定。有兩種方法強制固定,一種是用stackalloc分配在棧上,另一種是用fixed 分配在堆上。

轉載于:https://www.cnblogs.com/yefengmeander/archive/2011/01/05/2888040.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386266.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386266.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386266.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

百度、華為、京東、B站最新面試題匯集,實戰篇

前言 回顧一下自己這段時間的經歷&#xff0c;因公司突然通知裁員&#xff0c;我匆匆忙忙地出去面了幾家&#xff0c;但最終都沒有拿到offer&#xff0c;我感覺今年的寒冬有點冷。公司開始第二波裁員&#xff0c;我決定主動拿賠償走人。后續的面試過程我做了一些準備&#xff…

php 常用正則運算

$regx "/^[0-9]*$/"; var_dump(preg_match($regx, $phone));常用的正則運算&#xff1a; ?驗證數字&#xff1a;^[0-9]*$ ?驗證n位的數字&#xff1a;^\d{n}$ ?驗證至少n位數字&#xff1a;^\d{n,}$ ?驗證m-n位的數字&#xff1a;^\d{m,n}$ ?驗證零和非零開頭的…

百度、阿里、滴滴、新浪的面試心經總結,一線互聯網公司面經總結

開頭 技術的發展產生了程序員這個職位&#xff0c;從這些年各大互聯網公司曝光的一些員工收入水平來看&#xff0c;程序員的工資還是相對比較高的&#xff0c;可是我們在互聯網上還聽到了另外一種聲音&#xff0c;很多程序員想轉行&#xff0c;特別是大齡程序員&#xff0c;這…

go build編譯不同環境

#usage: go build [-o output] [-i] [build flags] [packages] go build的使用比較簡潔&#xff0c;所有的參數都可以忽略&#xff0c;直到只有go build&#xff0c;這個時候意味著使用當前目錄進行編譯&#xff0c;下面的幾條命令是等價的&#xff1a; go buildgo build .go b…

百度、阿里、滴滴、新浪的面試心經總結,源碼+原理+手寫框架

前言 作為一個程序員&#xff0c;如果你在新知識、新技術面前仍一無所知&#xff0c;依然吃著十多年前的老本&#xff0c;那你在知識技術上肯定落伍&#xff0c;如果又未能進入管理層面&#xff0c;那你肯定就會被長江的后浪拍在沙灘上了。 而不少與時俱進、善于學習的程序員…

LINQ to SQL

Moved to http://blog.tangcs.com/2008/10/06/linq-to-sql/轉載于:https://www.cnblogs.com/WarrenTang/archive/2008/10/06/1304727.html

目前最全的《Android面試題及解析》!面試真題解析

背景 慣例&#xff0c;先簡單陳述一下自己的&#xff0c;91年生人&#xff0c;164年三本畢業后在深圳工作&#xff0c;末流小公司&#xff0c;工資13k&#xff0c;無房&#xff0c;無車&#xff0c;無戶口。 那時候感覺生活也還行&#xff0c;父母有退休金&#xff0c;我基本…

有效的形成傳感器(執行器)的控制方式

其實為了增加閉環的話需要再增加一個傳感器&#xff0c;比如編碼器。 轉載于:https://www.cnblogs.com/yjphhw/p/11285145.html

直接上干貨!技術水平真的很重要!復習指南

開頭 25歲那年&#xff0c;我從京東離職&#xff0c;入職百度。 在百度認識了當時的架構師久哥&#xff08;T9級別&#xff09;&#xff0c;因為他的一番話&#xff0c;徹底改變了我的職業生涯&#xff0c;短短三年的時間&#xff0c;我從一枚普通程序員成長為別人眼中的技術…

實戰HMM-Viterbi角色標注地名識別

http://www.hankcs.com/nlp/ner/place-names-to-identify-actual-hmm-viterbi-role-labeling.html 命名實體識別&#xff08;Named Entity Recognition&#xff09;也是自然語言處理中的一個難關&#xff0c;特別是中文這樣沒有大小寫等固定形態的語言。上次介紹過《實戰HMM-Vi…

看完99%的人都學會了!9次Android面試經驗總結,我先收藏為敬

我們都是被圈養的人&#xff1f; 我的朋友程序員K&#xff0c;說他在電力行業的一家軟件公司做了八年Android開發&#xff0c;用到的各種技術&#xff0c;數據庫&#xff0c;網絡請求&#xff0c;事件傳遞&#xff0c;響應框架都很熟悉&#xff0c;甚至JNI/NDK/Framework&…

從外包公司到今日頭條offer,含BATJM大廠

前言 最近有不少人問我這樣一個問題&#xff1a;「我剛接觸編程&#xff0c;準備學習下Android開發&#xff0c;但是擔心現在市場飽和了&#xff0c;Android開發的前景怎么樣&#xff1f;」 想著可能有很多人都有這樣的擔心&#xff0c;于是就趕緊寫篇文章&#xff0c;來跟你…

PTA -- A1046 Shortest Distance

題意及思路 題意&#xff1a;有N個節點&#xff08;1至N&#xff09;&#xff0c;求給定的st號到en號的距離最小值&#xff0c;這些點構成一個環&#xff0c;即1->2 ... ->N ->1。 思路&#xff1a;第一步&#xff0c;預處理操作&#xff0c;以dis[ i ] 表示&#xff…

從外包公司到今日頭條offer,聰明人已經收藏了!

開頭 讓我們一起來看看&#xff0c;字節跳動的第三面&#xff0c;面試官都問了什么&#xff1f;&#xff08;第一二面的題目及答案已整理&#xff0c;需要的可以在文末領取&#xff09; 從七月中旬開始&#xff0c;我前前后后差不多一共投遞了八十份簡歷&#xff0c;到目前為…

程序從高版本降到2.0,數據集報錯 TypedTableBase

錯誤 命名空間“System.Data”中不存在類型或命名空間名稱“TypedTableBase”(是缺少程序集引用嗎?) 解決&#xff1a; 該錯誤出現在自動生成的XXX.Designer.cs里。 .NET 3.5 : public partial class T_OPERATOR_WLDataTable : global::System.Data.TypedTableBase<T_OPER…

從外包月薪5K到阿里月薪15K,原理+實戰+視頻+源碼

前言 轉眼間&#xff0c;2020 年已過去一大半了&#xff0c;2020 年很難&#xff0c;各企業裁員的消息蠻多的&#xff0c;降職&#xff0c;不發年終獎等等。2020 年確實是艱難的一年。然而生活總是要繼續&#xff0c;時間不給你喪的機會&#xff01;如果我們能堅持下來&#x…

C#編寫的發送手機短信的類庫 C#開發短信的方法和簡介 短信編程實例

發送手機短信源代碼(針對國內短信編碼) / ///文 件&#xff1a;PDUdecoding.cs ///概 要&#xff1a;針對國內短信編碼&#xff08;USC2&#xff09; ///組成結構&#xff1a;包含四個函數&#xff1a; /// smsDecodedCenterNumber(string srvCenterNumber) …

從新手到Flutter架構師,一篇就夠!吐血整理

在開始回答前&#xff0c;先簡單概括性地說說Linux現有的所有進程間IPC方式&#xff1a; 1. **管道&#xff1a;**在創建時分配一個page大小的內存&#xff0c;緩存區大小比較有限&#xff1b; 2. 消息隊列&#xff1a;信息復制兩次&#xff0c;額外的CPU消耗&#xff1b;不合…

小程序自定義組件中observer函數的應用

<!-- 單個數據監聽 --> <view>白菜</view> <view>價格&#xff1a;{{price}}</view> <!-- bindinput輸入時觸發方法 --> <view>數量&#xff1a; <input type"number" bindinputchangee value"{{num1}}">…

從新手到Flutter架構師,一篇就夠!學習路線+知識點梳理

前言 IT行業薪水高&#xff0c;這是眾所周知的&#xff0c;所以很多人大學都選擇IT相關專業&#xff0c;即使非該專業的人&#xff0c;畢業了也想去一個培訓機構鍍鍍金&#xff0c;進入這一行業。 但是有關這個行業35歲就退休的說法&#xff0c;也一直盛傳。 加上這幾年不斷…