日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#学习之unsafe

發布時間:2023/11/30 C# 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的C#学习之unsafe的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。