![C不安全代碼18_第1頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/9eafb818-a80f-4bf6-8ddc-3dd6b032b642/9eafb818-a80f-4bf6-8ddc-3dd6b032b6421.gif)
![C不安全代碼18_第2頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/9eafb818-a80f-4bf6-8ddc-3dd6b032b642/9eafb818-a80f-4bf6-8ddc-3dd6b032b6422.gif)
![C不安全代碼18_第3頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/9eafb818-a80f-4bf6-8ddc-3dd6b032b642/9eafb818-a80f-4bf6-8ddc-3dd6b032b6423.gif)
![C不安全代碼18_第4頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/9eafb818-a80f-4bf6-8ddc-3dd6b032b642/9eafb818-a80f-4bf6-8ddc-3dd6b032b6424.gif)
![C不安全代碼18_第5頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-2/23/9eafb818-a80f-4bf6-8ddc-3dd6b032b642/9eafb818-a80f-4bf6-8ddc-3dd6b032b6425.gif)
版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、18. 不安全代碼31318.1 不安全上下文31318.2 指針類(lèi)型31518.3 固定和可移動(dòng)變量31818.4 指針轉(zhuǎn)換31818.5 表達(dá)式中的指針319 指針間接尋址320 指針成員訪(fǎng)問(wèn)320 指針元素訪(fǎng)問(wèn)32118.5.4 address-of 運(yùn)算符322 指針遞增和遞減323 指針?biāo)阈g(shù)運(yùn)算323 指針比較324 sizeof 運(yùn)算符32418.6 fixed 語(yǔ)句32518.7 堆棧分配32818.8 動(dòng)態(tài)內(nèi)存分配3291. 不安全代碼如前面幾章所定義,核心 C# 語(yǔ)言沒(méi)有將指針列入它所支持的數(shù)據(jù)類(lèi)型,從而與 C 和 C+ 有著顯著的區(qū)別。作為替代,C# 提供了各種引用類(lèi)型,并
2、能夠創(chuàng)建可由垃圾回收器管理的對(duì)象。這種設(shè)計(jì)結(jié)合其他功能,使 C# 成為比 C 或 C+ 安全得多的語(yǔ)言。在核心 C# 語(yǔ)言中,不可能有未初始化的變量、“虛”指針或者超過(guò)數(shù)組的邊界對(duì)其進(jìn)行索引的表達(dá)式。這樣,以往總是不斷地?zé)_ C 和 C+ 程序的一系列錯(cuò)誤就不會(huì)再出現(xiàn)了。盡管實(shí)際上對(duì) C 或 C+ 中的每種指針類(lèi)型構(gòu)造,C# 都設(shè)置了與之對(duì)應(yīng)的引用類(lèi)型,但仍然會(huì)有一些場(chǎng)合需要訪(fǎng)問(wèn)指針類(lèi)型。例如,當(dāng)需要與基礎(chǔ)操作系統(tǒng)進(jìn)行交互、訪(fǎng)問(wèn)內(nèi)存映射設(shè)備,或?qū)崿F(xiàn)一些以時(shí)間為關(guān)鍵的算法時(shí),若沒(méi)有訪(fǎng)問(wèn)指針的手段,就不可能或者至少很難完成。為了滿(mǎn)足這樣的需求,C# 提供了編寫(xiě)不安全代碼 (unsafe code)
3、 的能力。在不安全代碼中,可以聲明和操作指針,可以在指針和整型之間執(zhí)行轉(zhuǎn)換,還可以獲取變量的地址,等等。在某種意義上,編寫(xiě)不安全代碼很像在 C# 程序中編寫(xiě) C 代碼。無(wú)論從開(kāi)發(fā)人員還是從用戶(hù)角度來(lái)看,不安全代碼事實(shí)上都是一種“安全”功能。不安全代碼必須用修飾符 unsafe 明確地標(biāo)記,這樣開(kāi)發(fā)人員就不會(huì)誤用不安全功能,而執(zhí)行引擎將確保不會(huì)在不受信任的環(huán)境中執(zhí)行不安全代碼。1.1 不安全上下文C# 的不安全功能僅用于不安全上下文中。不安全上下文是通過(guò)在類(lèi)型或成員的聲明中包含一個(gè) unsafe 修飾符或者通過(guò)使用 unsafe-statement 引入的: 類(lèi)、結(jié)構(gòu)、接口或委托的聲明可以包含一
4、個(gè) unsafe 修飾符,在這種情況下,該類(lèi)型聲明的整個(gè)文本范圍(包括類(lèi)、結(jié)構(gòu)或接口的體)被認(rèn)為是不安全上下文。 在字段、方法、屬性、事件、索引器、運(yùn)算符、實(shí)例構(gòu)造函數(shù)、析構(gòu)函數(shù)或靜態(tài)構(gòu)造函數(shù)的聲明中,也可以包含一個(gè) unsafe 修飾符,在這種情況下,該成員聲明的整個(gè)文本范圍被認(rèn)為是不安全上下文。 unsafe-statement 使得可以在 block 內(nèi)使用不安全上下文。該語(yǔ)句關(guān)聯(lián)的 block 的整個(gè)文本范圍被認(rèn)為是不安全上下文。下面顯示了關(guān)聯(lián)的語(yǔ)法擴(kuò)展。為簡(jiǎn)潔起見(jiàn),用省略號(hào) (.) 表示前幾章中出現(xiàn)過(guò)的產(chǎn)生式。class-modifier:.unsafestruct-modifier
5、:.unsafeinterface-modifier:.unsafedelegate-modifier:.unsafefield-modifier:.unsafemethod-modifier:.unsafeproperty-modifier:.unsafeevent-modifier:.unsafeindexer-modifier:.unsafeoperator-modifier:.unsafeconstructor-modifier:.unsafedestructor-declaration:attributesopt externopt unsafeopt identifier ( )
6、destructor-bodyattributesopt unsafeopt externopt identifier ( ) destructor-bodystatic-constructor-modifiers:externopt unsafeopt staticunsafeopt externopt staticexternopt static unsafeopt externopt static unsafeopt static externopt unsafeoptstatic unsafeopt externoptembedded-statement:.unsafe-stateme
7、ntunsafe-statement:unsafe block在下面的示例中public unsafe struct Nodepublic int Value;public Node* Left;public Node* Right;在結(jié)構(gòu)聲明中指定的 unsafe 修飾符導(dǎo)致該結(jié)構(gòu)聲明的整個(gè)文本范圍成為不安全上下文。因此,可以將 Left 和 Right 字段聲明為指針類(lèi)型。上面的示例還可以編寫(xiě)為public struct Nodepublic int Value;public unsafe Node* Left;public unsafe Node* Right;此處,字段聲明中的 uns
8、afe 修飾符導(dǎo)致這些聲明被認(rèn)為是不安全上下文。除了建立不安全上下文從而允許使用指針類(lèi)型外,unsafe 修飾符對(duì)類(lèi)型或成員沒(méi)有影響。在下面的示例中public class Apublic unsafe virtual void F() char* p;.public class B: Apublic override void F() base.F();.A 中 F 方法上的 unsafe 修飾符直接導(dǎo)致 F 的文本范圍成為不安全上下文并可以在其中使用語(yǔ)言的不安全功能。在 B 中對(duì) F 的重寫(xiě)中,不需要重新指定 unsafe 修飾符,除非 B 中的 F 方法本身需要訪(fǎng)問(wèn)不安全功能。當(dāng)指針類(lèi)型
9、是方法簽名的一部分時(shí),情況略有不同public unsafe class Apublic virtual void F(char* p) .public class B: Apublic unsafe override void F(char* p) .此處,由于 F 的簽名包括指針類(lèi)型,因此它只能出現(xiàn)在不安全上下文中。然而,為設(shè)置此不安全上下文,既可以將整個(gè)類(lèi)設(shè)置為不安全的(如 A 中的情況),也可以?xún)H在方法聲明中包含一個(gè) unsafe 修飾符(如 B 中的情況)。1.2 指針類(lèi)型在不安全上下文中,type(第 Error! Reference source not found. 章)可以是
10、 pointer-type,也可以是 value-type 或 reference-type。但是,pointer-type 也能在不安全上下文以外的 typeof 表達(dá)式(第 Error! Reference source not found. 節(jié))中使用,因?yàn)榇祟?lèi)使用不是不安全的。type:value-typereference-typepointer-typepointer-type 可表示為 unmanaged-type 后跟一個(gè) * 標(biāo)記,或者關(guān)鍵字 void 后跟一個(gè) * 標(biāo)記:pointer-type:unmanaged-type *void *unmanaged-type:ty
11、pe指針類(lèi)型中,在 * 前面指定的類(lèi)型稱(chēng)為該指針類(lèi)型的目標(biāo)類(lèi)型 (referent type)。它表示該指針類(lèi)型的值所指向的變量的類(lèi)型。與引用(引用類(lèi)型的值)不同,指針不受垃圾回收器跟蹤(垃圾回收器并不知曉指針和它們指向的數(shù)據(jù))。出于此原因,不允許指針指向引用或者包含引用的結(jié)構(gòu),并且指針的目標(biāo)類(lèi)型必須是 unmanaged-type。unmanaged-type 是任何不是 reference-type 并且在任何嵌套級(jí)別都不包含 reference-type 字段的類(lèi)型。換句話(huà)說(shuō),unmanaged-type 是下列類(lèi)型之一: sbyte、byte、short、ushort、int、uint
12、、long、ulong、char、float、double、decimal 或 bool。 任何 enum-type。 任何 pointer-type。 任何由用戶(hù)定義的只包含 unmanaged-type 字段的 struct-type。將指針和引用進(jìn)行混合使用時(shí)的基本規(guī)則是;引用(對(duì)象)的目標(biāo)可以包含指針,但指針的目標(biāo)不能包含引用。下表給出了一些指針類(lèi)型的示例:示例說(shuō)明byte*指向 byte 的指針char*指向 char 的指針int*指向 int 的指針的指針int*一維數(shù)組,它的元素是指向 int 的指針void*指向未知類(lèi)型的指針對(duì)于某個(gè)給定實(shí)現(xiàn),所有的指針類(lèi)型都必須具有相同的大
13、小和表示形式。與 C 和 C+ 不同,在 C# 中,當(dāng)在同一聲明中聲明多個(gè)指針時(shí),* 只與基礎(chǔ)類(lèi)型寫(xiě)在一起,而不充當(dāng)每個(gè)指針名稱(chēng)的前綴標(biāo)點(diǎn)符號(hào)。例如int* pi, pj;/ NOT as int *pi, *pj;類(lèi)型為 T* 的一個(gè)指針的值表示類(lèi)型為 T 的一個(gè)變量的地址。指針間接尋址運(yùn)算符 * (第 1.5.1 節(jié)) 可用于訪(fǎng)問(wèn)此變量。例如,給定int* 類(lèi)型的變量 P,則表達(dá)式 *P 表示 int 變量,該變量的地址就是 P 的值。 與對(duì)象引用類(lèi)似,指針可以是 null。如果將間接尋址運(yùn)算符應(yīng)用于 null 指針,則其行為將由實(shí)現(xiàn)自己定義。值為 null 的指針表示為將該指針的所有位都
14、置零。void* 類(lèi)型表示指向未知類(lèi)型的指針。因?yàn)槟繕?biāo)類(lèi)型是未知的,所以間接尋址運(yùn)算符不能應(yīng)用于 void* 類(lèi)型的指針,也不能對(duì)這樣的指針執(zhí)行任何算術(shù)運(yùn)算。但是,void* 類(lèi)型的指針可以強(qiáng)制轉(zhuǎn)換為任何其他指針類(lèi)型(反之亦然)。指針類(lèi)型是一個(gè)單獨(dú)類(lèi)別的類(lèi)型。與引用類(lèi)型和值類(lèi)型不同,指針類(lèi)型不從 object 繼承,而且不存在指針類(lèi)型和 object 之間的轉(zhuǎn)換。具體而言,指針不支持裝箱和拆箱(第 Error! Reference source not found. 節(jié))操作。但是,允許在不同指針類(lèi)型之間以及指針類(lèi)型與整型之間進(jìn)行轉(zhuǎn)換。在第 1.4 節(jié)中對(duì)此進(jìn)行了描述。pointer-type
15、 可用作易失字段的類(lèi)型(第 Error! Reference source not found. 節(jié))。雖然指針可以作為 ref 或 out 參數(shù)傳遞,但這樣做可能會(huì)導(dǎo)致未定義的行為,例如,指針可能被設(shè)置為指向一個(gè)局部變量,而當(dāng)調(diào)用方法返回時(shí),該局部變量可能已不存在了;或者指針曾指向一個(gè)固定對(duì)象,但當(dāng)調(diào)用方法返回時(shí),該對(duì)象不再是固定的了。例如:using System;class Teststatic int value = 20;unsafe static void F(out int* pi1, ref int* pi2) int i = 10;pi1 = &i;fixed (int* p
16、j = &value) / .pi2 = pj;static void Main() int i = 10;unsafe int* px1;int* px2 = &i;F(out px1, ref px2);Console.WriteLine(*px1 = 0, *px2 = 1,*px1, *px2);/ undefined behavior方法可以返回某一類(lèi)型的值,而該類(lèi)型可以是指針。例如,給定一個(gè)指向連續(xù)的 int 值序列的指針、該序列的元素個(gè)數(shù),和另外一個(gè) int 值 (value),下面的方法將在該整數(shù)序列中查找與該 value 匹配的值,若找到匹配項(xiàng),則返回該匹配項(xiàng)的地址;否則,它
17、將返回 null:unsafe static int* Find(int* pi, int size, int value) for (int i = 0; i 運(yùn)算符可用于通過(guò)指針訪(fǎng)問(wèn)結(jié)構(gòu)的成員(第 1.5.2 節(jié))。 運(yùn)算符可用于索引指針(第 1.5.3 節(jié))。 & 運(yùn)算符可用于獲取變量的地址(第 1.5.4 節(jié))。 + 和 - 運(yùn)算符可以用于遞增和遞減指針(第 1.5.5 節(jié))。 + 和 - 運(yùn)算符可用于執(zhí)行指針?biāo)阈g(shù)運(yùn)算(第 1.5.6 節(jié))。 =、!=、 運(yùn)算符可以用于比較指針(第 1.5.7 節(jié))。 stackalloc 運(yùn)算符可用于從調(diào)用堆棧(第 1.7 節(jié))中分配內(nèi)存。 fixe
18、d 語(yǔ)句可用于臨時(shí)固定一個(gè)變量,以便可以獲取它的地址(第 1.6 節(jié))。1.3 固定和可移動(dòng)變量address-of 運(yùn)算符(第 1.5.4 節(jié))和 fixed 語(yǔ)句(第 18.6 節(jié))將變量劃分為兩個(gè)類(lèi)別:固定變量 (fixed variable) 和可移動(dòng)變量 (moveable variable)。固定變量駐留在不受垃圾回收器的操作影響的存儲(chǔ)位置中。(固定變量的示例包括局部變量、值參數(shù)和由取消指針引用而創(chuàng)建的變量。)另一方面,可移動(dòng)變量則駐留在會(huì)被垃圾回收器重定位或處置的存儲(chǔ)位置中。(可移動(dòng)變量的示例包括對(duì)象中的字段和數(shù)組的元素。)& 運(yùn)算符(第 1.5.4 節(jié))允許不受限制地獲取固定變
19、量的地址。但是,由于可移動(dòng)變量會(huì)受到垃圾回收器的重定位或處置,因此可移動(dòng)變量的地址只能使用 fixed 語(yǔ)句(第 1.6 節(jié))獲取,而且該地址只在此 fixed 語(yǔ)句的生存期內(nèi)有效。準(zhǔn)確地說(shuō),固定變量是下列之一: 用引用局部變量或值參數(shù)的 simple-name(第 Error! Reference source not found. 節(jié))表示的變量。 用 V.I 形式的 member-access(第 Error! Reference source not found. 節(jié))表示的變量,其中 V 是 struct-type 的固定變量。 用 *P 形式的 pointer-indirectio
20、n-expression(第 1.5.1 節(jié))、P-I 形式的 pointer-member-access(第 節(jié))或 PE 形式的 pointer-element-access(第 節(jié))表示的變量。所有其他變量都屬于可移動(dòng)變量。請(qǐng)注意靜態(tài)字段屬于可移動(dòng)變量。還請(qǐng)注意即使賦予 ref 或 out 形參的實(shí)參是固定變量,它們?nèi)詫儆诳梢苿?dòng)變量。最后請(qǐng)注意,由取消指針引用而產(chǎn)生的變量總是屬于固定變量。1.4 指針轉(zhuǎn)換在不安全上下文中,可供使用的隱式轉(zhuǎn)換的集合(第 Error! Reference source not found. 節(jié))也擴(kuò)展為包括以下隱式指針轉(zhuǎn)換: 從任何 pointer-type
21、 到 void* 類(lèi)型。 從 null 類(lèi)型到任何 pointer-type。另外,在不安全上下文中,可供使用的顯式轉(zhuǎn)換的集合(第 Error! Reference source not found. 節(jié))也擴(kuò)展為包括以下顯式指針轉(zhuǎn)換: 從任何 pointer-type 到任何其他 pointer-type。 從 sbyte、byte、short、ushort、int、uint、long 或 ulong 到任何 pointer-type。 從任何 pointer-type 到 sbyte、byte、short、ushort、int、uint、long 或 ulong。最后,在不安全上下文中,標(biāo)
22、準(zhǔn)隱式轉(zhuǎn)換的集合(第 Error! Reference source not found. 節(jié))包括以下指針轉(zhuǎn)換: 從任何 pointer-type 到 void* 類(lèi)型。兩個(gè)指針類(lèi)型之間的轉(zhuǎn)換永遠(yuǎn)不會(huì)更改實(shí)際的指針值。換句話(huà)說(shuō),從一個(gè)指針類(lèi)型到另一個(gè)指針類(lèi)型的轉(zhuǎn)換不會(huì)影響由指針給出的基礎(chǔ)地址。當(dāng)一個(gè)指針類(lèi)型被轉(zhuǎn)換為另一個(gè)指針類(lèi)型時(shí),如果沒(méi)有將得到的指針正確地對(duì)指向的類(lèi)型對(duì)齊,則當(dāng)結(jié)果被取消引用時(shí),該行為將是未定義的。一般情況下,“正確對(duì)齊”的概念是可傳遞的:如果指向類(lèi)型 A 的指針正確地與指向類(lèi)型 B 的指針對(duì)齊,而此指向類(lèi)型 B 的指針又正確地與指向類(lèi)型 C 的指針對(duì)齊,則指向類(lèi)型 A 的
23、指針將正確地與指向類(lèi)型 C 的指針對(duì)齊。請(qǐng)考慮下列情況,其中具有一個(gè)類(lèi)型的變量被通過(guò)指向一個(gè)不同類(lèi)型的指針訪(fǎng)問(wèn):char c = A;char* pc = &c;void* pv = pc;int* pi = (int*)pv;int i = *pi;/ undefined*pi = 123456;/ undefined當(dāng)一個(gè)指針類(lèi)型被轉(zhuǎn)換為指向字節(jié)的指針時(shí),轉(zhuǎn)換后的指針將指向原來(lái)所指變量的地址中的最低尋址字節(jié)。連續(xù)增加該變換后的指針(最大可達(dá)到該變量所占內(nèi)存空間的大?。?,將產(chǎn)生指向該變量的其他字節(jié)的指針。例如,下列方法將 double 型變量中的八個(gè)字節(jié)的每一個(gè)顯示為一個(gè)十六進(jìn)制值:usin
24、g System;class Testunsafe static void Main() double d = 123.456e23;unsafe byte* pb = (byte*)&d;for (int i = 0; i ”標(biāo)記,最后是一個(gè) identifier。pointer-member-access:primary-expression - identifier在 P-I 形式的指針成員訪(fǎng)問(wèn)中,P 必須是除 void* 以外的某個(gè)指針類(lèi)型的表達(dá)式,而 I 必須表示 P 所指向的類(lèi)型的可訪(fǎng)問(wèn)成員。P-I 形式的指針成員訪(fǎng)問(wèn)的計(jì)算方式與 (*P).I 完全相同。有關(guān)指針間接尋址運(yùn)算符 (
25、*) 的說(shuō)明,請(qǐng)參見(jiàn)第 1.5.1 節(jié)。有關(guān)成員訪(fǎng)問(wèn)運(yùn)算符 (.) 的說(shuō)明,請(qǐng)參見(jiàn)第 Error! Reference source not found. 節(jié)。在下面的示例中using System;struct Pointpublic int x;public int y;public override string ToString() return ( + x + , + y + );class Teststatic void Main() Point point;unsafe Point* p = &point;p-x = 10;p-y = 20;Console.WriteLine(p
26、-ToString();- 運(yùn)算符用于通過(guò)指針訪(fǎng)問(wèn)結(jié)構(gòu)中的字段和調(diào)用結(jié)構(gòu)中的方法。由于 P-I 操作完全等效于 (*P).I,因此 Main 方法可以等效地編寫(xiě)為:class Teststatic void Main() Point point;unsafe Point* p = &point;(*p).x = 10;(*p).y = 20;Console.WriteLine(*p).ToString();1.5.3 指針元素訪(fǎng)問(wèn)pointer-element-access 包括一個(gè) primary-no-array-creation-expression,后跟一個(gè)用“”和“”括起來(lái)的表達(dá)式。
27、pointer-element-access:primary-no-array-creation-expression expression 在 PE 形式的指針元素訪(fǎng)問(wèn)中,P 必須是 void* 以外的指針類(lèi)型的表達(dá)式,而 E 則必須是可以隱式轉(zhuǎn)換為 int、uint、long 或 ulong 的類(lèi)型的表達(dá)式。PE 形式的指針元素訪(fǎng)問(wèn)的計(jì)算方式與 *(P + E) 完全相同。有關(guān)指針間接尋址運(yùn)算符 (*) 的說(shuō)明,請(qǐng)參見(jiàn)第 1.5.1 節(jié)。有關(guān)指針加法運(yùn)算符 (+) 的說(shuō)明,請(qǐng)參見(jiàn)第 1.5.6 節(jié)。在下面的示例中class Teststatic void Main() unsafe cha
28、r* p = stackalloc char256;for (int i = 0; i 256; i+) pi = (char)i;指針元素訪(fǎng)問(wèn)用于在 for 循環(huán)中初始化字符緩沖區(qū)。由于 PE 操作完全等效于 *(P + E),因此示例可以等效地編寫(xiě)為:class Teststatic void Main() unsafe char* p = stackalloc char256;for (int i = 0; i 256; i+) *(p + i) = (char)i;指針元素訪(fǎng)問(wèn)運(yùn)算符不能檢驗(yàn)是否發(fā)生訪(fǎng)問(wèn)越界錯(cuò)誤,而且當(dāng)訪(fǎng)問(wèn)超出邊界的元素時(shí)行為是未定義的。這與 C 和 C+ 相同。1.5
29、.4 address-of 運(yùn)算符addressof-expression 包含一個(gè)“and”符 (&),后跟一個(gè) unary-expression。addressof-expression:& unary-expression如果給定類(lèi)型為 T 且屬于固定變量(第 1.3 節(jié))的表達(dá)式 E,構(gòu)造 &E 將計(jì)算由 E 給出的變量的地址。計(jì)算的結(jié)果是一個(gè)類(lèi)型為 T* 的值。如果 E 不屬于變量,如果 E 屬于只讀局部變量,或如果 E 表示可移的變量,則將發(fā)生編譯時(shí)錯(cuò)誤。在最后一種情況中,可以先利用固定語(yǔ)句(第 1.6 節(jié))臨時(shí)“固定”該變量,再獲取它的地址。如第 Error! Reference
30、 source not found. 節(jié)中所述,如果在實(shí)例構(gòu)造函數(shù)或靜態(tài)構(gòu)造函數(shù)之外,在結(jié)構(gòu)或類(lèi)中定義了 readonly 字段,則該字段被認(rèn)為是一個(gè)值,而不是變量。因此,無(wú)法獲取它的地址。與此類(lèi)似,無(wú)法獲取常量的地址。& 運(yùn)算符不要求它的參數(shù)先被明確賦值,但是在執(zhí)行了 & 操作后,該運(yùn)算符所應(yīng)用于的那個(gè)變量在此操作發(fā)生的執(zhí)行路徑中被“認(rèn)為是”已經(jīng)明確賦值的。這意味著,由程序員負(fù)責(zé)確保在相關(guān)的上下文中對(duì)該變量實(shí)際進(jìn)行合適的初始化。在下面的示例中using System;class Teststatic void Main() int i;unsafe int* p = &i;*p = 123;
31、Console.WriteLine(i);初始化 p 的代碼執(zhí)行了 &i 操作,此后 i 被認(rèn)為是明確賦值的。對(duì) *p 的賦值實(shí)際上是初始化了 i,但設(shè)置此初始化是程序員的責(zé)任,而且如果移除此賦值語(yǔ)句,也不會(huì)發(fā)生編譯時(shí)錯(cuò)誤。上述 & 運(yùn)算符的明確賦值規(guī)則可以避免局部變量的冗余初始化。例如,許多外部 API 要求獲取指向結(jié)構(gòu)的指針,而由此 API 來(lái)填充該結(jié)構(gòu)。對(duì)此類(lèi) API 進(jìn)行的調(diào)用通常會(huì)傳遞局部結(jié)構(gòu)變量的地址,而如果沒(méi)有上述規(guī)則,則將需要對(duì)此結(jié)構(gòu)變量進(jìn)行冗余初始化。1.5.5 指針遞增和遞減在不安全上下文中,+ 和 - 運(yùn)算符(第 Error! Reference source not f
32、ound. 節(jié)和第 節(jié))可以應(yīng)用于除 void* 以外的所有類(lèi)型的指針變量。因此,為每個(gè)指針類(lèi)型 T* 都隱式定義了下列運(yùn)算符:T* operator +(T* x);T* operator -(T* x);這些運(yùn)算符分別產(chǎn)生與 x + 1 和 x - 1(第 1.5.6 節(jié))相同的結(jié)果。換句話(huà)說(shuō),對(duì)于 T* 類(lèi)型的指針變量,+ 運(yùn)算符將該變量的地址加上 sizeof(T),而 - 運(yùn)算符則將該變量的地址減去 sizeof(T)。如果指針遞增或遞減運(yùn)算的結(jié)果超過(guò)指針類(lèi)型的域,則結(jié)果是由實(shí)現(xiàn)定義的,但不會(huì)產(chǎn)生異常。1.5.6 指針?biāo)阈g(shù)運(yùn)算在不安全上下文中,+ 和 - 運(yùn)算符(第 Error! R
33、eference source not found. 節(jié)和第 節(jié))可以應(yīng)用于除 void* 以外的所有指針類(lèi)型的值。因此,為每個(gè)指針類(lèi)型 T* 都隱式定義了下列運(yùn)算符:T* operator +(T* x, int y);T* operator +(T* x, uint y);T* operator +(T* x, long y);T* operator +(T* x, ulong y);T* operator +(int x, T* y);T* operator +(uint x, T* y);T* operator +(long x, T* y);T* operator +(ulong x
34、, T* y);T* operator (T* x, int y);T* operator (T* x, uint y);T* operator (T* x, long y);T* operator (T* x, ulong y);long operator (T* x, T* y);給定指針類(lèi)型 T* 的表達(dá)式 P 和類(lèi)型 int、uint、long 或 ulong 的表達(dá)式 N,表達(dá)式 P + N 和 N + P 的計(jì)算結(jié)果是一個(gè)屬于類(lèi)型 T* 的指針值,該值等于由 P 給出的地址加上 N * sizeof(T)。與此類(lèi)似,表達(dá)式 P - N 的計(jì)算結(jié)果也是一個(gè)屬于類(lèi)型 T* 的指針值,該
35、值等于由 P 給出的地址減去 N * sizeof(T)。給定指針類(lèi)型 T* 的兩個(gè)表達(dá)式 P 和 Q,表達(dá)式 P Q 將先計(jì)算 P 和 Q 給出的地址之間的差,然后用 sizeof(T) 去除該差值。計(jì)算結(jié)果的類(lèi)型始終為 long。實(shí)際上,P - Q 的計(jì)算過(guò)程是:(long)(P) - (long)(Q) / sizeof(T)。例如:using System;class Teststatic void Main() unsafe int* values = stackalloc int20;int* p = &values1;int* q = &values15;Console.Writ
36、eLine(p - q = 0, p - q);Console.WriteLine(q - p = 0, q - p);生成以下輸出:p - q = -14q - p = 14如果在執(zhí)行上述指針?biāo)惴〞r(shí),計(jì)算結(jié)果超越該指針類(lèi)型的域,則將以實(shí)現(xiàn)所定義的方式截?cái)嘟Y(jié)果,但是不會(huì)產(chǎn)生異常。1.5.7 指針比較在不安全上下文中,=、!=、 運(yùn)算符(第 Error! Reference source not found. 節(jié))可以應(yīng)用于所有指針類(lèi)型的值。指針比較運(yùn)算符有:bool operator =(void* x, void* y);bool operator !=(void* x, void* y);
37、bool operator (void* x, void* y);bool operator =(void* x, void* y);由于存在從任何指針類(lèi)型到 void* 類(lèi)型的隱式轉(zhuǎn)換,因此可以使用這些運(yùn)算符來(lái)比較任何指針類(lèi)型的操作數(shù)。比較運(yùn)算符像比較無(wú)符號(hào)整數(shù)一樣比較兩個(gè)操作數(shù)給出的地址。1.5.8 sizeof 運(yùn)算符sizeof 運(yùn)算符返回由給定類(lèi)型的變量占用的字節(jié)數(shù)。被指定為 sizeof 的操作數(shù)的類(lèi)型必須為 unmanaged-type(第 1.2 節(jié))。sizeof-expression:sizeof ( unmanaged-type )sizeof 運(yùn)算符的結(jié)果是 int 類(lèi)
38、型的值。對(duì)于某些預(yù)定義類(lèi)型,sizeof 運(yùn)算符將產(chǎn)生如下表所示的常數(shù)值。表達(dá)式結(jié)果sizeof(sbyte)1sizeof(byte)1sizeof(short)2sizeof(ushort)2sizeof(int)4sizeof(uint)4sizeof(long)8sizeof(ulong)8sizeof(char)2sizeof(float)4sizeof(double)8sizeof(bool)1對(duì)于所有其他類(lèi)型,sizeof 運(yùn)算符的結(jié)果是由實(shí)現(xiàn)定義的,并且屬于值而不是常量。一個(gè)結(jié)構(gòu)所屬的各個(gè)成員以什么順序被裝入該結(jié)構(gòu)中,沒(méi)有明確規(guī)定。出于對(duì)齊的目的,在結(jié)構(gòu)的開(kāi)頭、結(jié)構(gòu)內(nèi)以及結(jié)構(gòu)的
39、結(jié)尾處可以插入一些未命名的填充位。這些填充位的內(nèi)容是不確定的。當(dāng) sizeof 應(yīng)用于具有結(jié)構(gòu)類(lèi)型的操作數(shù)時(shí),結(jié)果是該類(lèi)型變量所占的字節(jié)總數(shù)(包括所有填充位在內(nèi))。1.6 fixed 語(yǔ)句在不安全上下文中,embedded-statement(第 Error! Reference source not found. 章)產(chǎn)生式允許使用一個(gè)附加結(jié)構(gòu)即 fixed 語(yǔ)句,該語(yǔ)句用于“固定”可移動(dòng)變量,從而使該變量的地址在語(yǔ)句的持續(xù)時(shí)間內(nèi)保持不變。embedded-statement:.fixed-statementfixed-statement:fixed ( pointer-type fixed
40、-pointer-declarators ) embedded-statementfixed-pointer-declarators:fixed-pointer-declaratorfixed-pointer-declarators , fixed-pointer-declaratorfixed-pointer-declarator:identifier = fixed-pointer-initializerfixed-pointer-initializer:& variable-referenceexpression如上述產(chǎn)生式所述,每個(gè) fixed-pointer-declarator 聲
41、明一個(gè)給定 pointer-type 的局部變量,并使用由相應(yīng)的 fixed-pointer-initializer 計(jì)算的地址初始化該局部變量。在 fixed 語(yǔ)句中聲明的局部變量的可訪(fǎng)問(wèn)范圍僅限于:在該變量聲明右邊的所有 fixed-pointer-initializer 中,以及在該 fixed 語(yǔ)句的 embedded-statement 中。由 fixed 語(yǔ)句聲明的局部變量被視為只讀。如果嵌入語(yǔ)句試圖修改此局部變量(通過(guò)賦值或 + 和 - 運(yùn)算符)或者將它作為 ref 或 out 參數(shù)傳遞,則將出現(xiàn)編譯時(shí)錯(cuò)誤。fixed-pointer-initializer 可以是下列之一: “
42、&”標(biāo)記,后跟一個(gè) variable-reference(第 Error! Reference source not found. 節(jié)),它引用非托管類(lèi)型 T 的可移動(dòng)變量(第 18.3 節(jié)),前提是類(lèi)型 T* 可以隱式轉(zhuǎn)換為 fixed 語(yǔ)句中給出的指針類(lèi)型。在這種情況下,初始值設(shè)定項(xiàng)將計(jì)算給定變量的地址,而 fixed 語(yǔ)句在生存期內(nèi)將保證該變量的地址不變。 元素類(lèi)型為非托管類(lèi)型 T 的 array-type 的表達(dá)式,前提是類(lèi)型 T* 可隱式轉(zhuǎn)換為 fixed 語(yǔ)句中給出的指針類(lèi)型。在這種情況下,初始值設(shè)定項(xiàng)將計(jì)算數(shù)組中第一個(gè)元素的地址,而 fixed 語(yǔ)句在生存期內(nèi)將保證整個(gè)數(shù)組的地址
43、保持不變。如果數(shù)組表達(dá)式為 null 或者數(shù)組具有零個(gè)元素,則 fixed 語(yǔ)句的行為由實(shí)現(xiàn)定義。 string 類(lèi)型的表達(dá)式,前提是類(lèi)型 char* 可以隱式轉(zhuǎn)換為 fixed 語(yǔ)句中給出的指針類(lèi)型。在這種情況下,初始值設(shè)定項(xiàng)將計(jì)算字符串中第一個(gè)字符的地址,而 fixed 語(yǔ)句在生存期內(nèi)將保證整個(gè)字符串的地址不變。如果字符串表達(dá)式為 null,則 fixed 語(yǔ)句的行為由實(shí)現(xiàn)定義。對(duì)于每個(gè)由 fixed-pointer-initializer 計(jì)算的地址,fixed 語(yǔ)句確保由該地址引用的變量在 fixed 語(yǔ)句的生存期內(nèi)不會(huì)被垃圾回收器重定位或者處置。例如,如果由 fixed-pointer-initializer 計(jì)算的地址引用對(duì)象的字段或數(shù)組實(shí)例的元素,fixed 語(yǔ)句將保證包含該字段或元素的對(duì)象實(shí)例本身也不會(huì)在該語(yǔ)句的生存期內(nèi)被重定位或者處置。確保由 fixed 語(yǔ)句創(chuàng)建的指針在執(zhí)行這些語(yǔ)句之后不再存在是程序員的責(zé)任。例如,當(dāng) fixed 語(yǔ)句創(chuàng)建的指針被傳遞到外部 API 時(shí),確保 API 不會(huì)在內(nèi)存中保留這些指針是程序員的
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025至2030年中國(guó)皮帶轉(zhuǎn)送線(xiàn)數(shù)據(jù)監(jiān)測(cè)研究報(bào)告
- 2025至2030年中國(guó)外罩?jǐn)?shù)據(jù)監(jiān)測(cè)研究報(bào)告
- 2025年中國(guó)高速輪轉(zhuǎn)膠印紙市場(chǎng)調(diào)查研究報(bào)告
- 商業(yè)綜合體商戶(hù)支持與服務(wù)體系建設(shè)考核試卷
- 墨水在食品包裝印刷中的安全性考核試卷
- 樂(lè)器維修與調(diào)律考核試卷
- 技術(shù)服務(wù)綠色能源技術(shù)創(chuàng)新考核試卷
- 2025-2030年發(fā)光服裝定制行業(yè)跨境出海戰(zhàn)略研究報(bào)告
- 2025-2030年變形概念車(chē)設(shè)計(jì)與展示行業(yè)跨境出海戰(zhàn)略研究報(bào)告
- 2025-2030年可折疊畫(huà)紙支架企業(yè)制定與實(shí)施新質(zhì)生產(chǎn)力戰(zhàn)略研究報(bào)告
- 2024-2025學(xué)年人教版生物八年級(jí)上冊(cè)期末綜合測(cè)試卷
- GB/T 709-2019熱軋鋼板和鋼帶的尺寸、外形、重量及允許偏差
- GB/T 14177-2003林業(yè)機(jī)械便攜式割灌機(jī)和割草機(jī)試驗(yàn)方法
- FZ/T 54007-2019錦綸6彈力絲
- DB11-T 291-2022日光溫室建造規(guī)范
- 2021-2022學(xué)年山東省淄博市高二(下)期末英語(yǔ)試卷(附答案詳解)
- 北師大版高中數(shù)學(xué)選修4-6初等數(shù)論初步全套課件
- 外貿(mào)業(yè)務(wù)員面試試卷
- 紀(jì)檢知識(shí)答題測(cè)試題及答案
- 創(chuàng)傷急救-止血、包扎課件
- 大數(shù)據(jù)背景下網(wǎng)絡(luò)輿情成因及治理
評(píng)論
0/150
提交評(píng)論