




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、18. 不安全代碼31318.1 不安全上下文31318.2 指針類型31518.3 固定和可移動變量31818.4 指針轉(zhuǎn)換31818.5 表達(dá)式中的指針319 指針間接尋址320 指針成員訪問320 指針元素訪問32118.5.4 address-of 運(yùn)算符322 指針遞增和遞減323 指針?biāo)阈g(shù)運(yùn)算323 指針比較324 sizeof 運(yùn)算符32418.6 fixed 語句32518.7 堆棧分配32818.8 動態(tài)內(nèi)存分配3291. 不安全代碼如前面幾章所定義,核心 C# 語言沒有將指針列入它所支持的數(shù)據(jù)類型,從而與 C 和 C+ 有著顯著的區(qū)別。作為替代,C# 提供了各種引用類型,并
2、能夠創(chuàng)建可由垃圾回收器管理的對象。這種設(shè)計結(jié)合其他功能,使 C# 成為比 C 或 C+ 安全得多的語言。在核心 C# 語言中,不可能有未初始化的變量、“虛”指針或者超過數(shù)組的邊界對其進(jìn)行索引的表達(dá)式。這樣,以往總是不斷地?zé)_ C 和 C+ 程序的一系列錯誤就不會再出現(xiàn)了。盡管實(shí)際上對 C 或 C+ 中的每種指針類型構(gòu)造,C# 都設(shè)置了與之對應(yīng)的引用類型,但仍然會有一些場合需要訪問指針類型。例如,當(dāng)需要與基礎(chǔ)操作系統(tǒng)進(jìn)行交互、訪問內(nèi)存映射設(shè)備,或?qū)崿F(xiàn)一些以時間為關(guān)鍵的算法時,若沒有訪問指針的手段,就不可能或者至少很難完成。為了滿足這樣的需求,C# 提供了編寫不安全代碼 (unsafe code)
3、 的能力。在不安全代碼中,可以聲明和操作指針,可以在指針和整型之間執(zhí)行轉(zhuǎn)換,還可以獲取變量的地址,等等。在某種意義上,編寫不安全代碼很像在 C# 程序中編寫 C 代碼。無論從開發(fā)人員還是從用戶角度來看,不安全代碼事實(shí)上都是一種“安全”功能。不安全代碼必須用修飾符 unsafe 明確地標(biāo)記,這樣開發(fā)人員就不會誤用不安全功能,而執(zhí)行引擎將確保不會在不受信任的環(huán)境中執(zhí)行不安全代碼。1.1 不安全上下文C# 的不安全功能僅用于不安全上下文中。不安全上下文是通過在類型或成員的聲明中包含一個 unsafe 修飾符或者通過使用 unsafe-statement 引入的: 類、結(jié)構(gòu)、接口或委托的聲明可以包含一
4、個 unsafe 修飾符,在這種情況下,該類型聲明的整個文本范圍(包括類、結(jié)構(gòu)或接口的體)被認(rèn)為是不安全上下文。 在字段、方法、屬性、事件、索引器、運(yùn)算符、實(shí)例構(gòu)造函數(shù)、析構(gòu)函數(shù)或靜態(tài)構(gòu)造函數(shù)的聲明中,也可以包含一個 unsafe 修飾符,在這種情況下,該成員聲明的整個文本范圍被認(rèn)為是不安全上下文。 unsafe-statement 使得可以在 block 內(nèi)使用不安全上下文。該語句關(guān)聯(lián)的 block 的整個文本范圍被認(rèn)為是不安全上下文。下面顯示了關(guān)聯(lián)的語法擴(kuò)展。為簡潔起見,用省略號 (.) 表示前幾章中出現(xiàn)過的產(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)聲明的整個文本范圍成為不安全上下文。因此,可以將 Left 和 Right 字段聲明為指針類型。上面的示例還可以編寫為public struct Nodepublic int Value;public unsafe Node* Left;public unsafe Node* Right;此處,字段聲明中的 uns
8、afe 修飾符導(dǎo)致這些聲明被認(rèn)為是不安全上下文。除了建立不安全上下文從而允許使用指針類型外,unsafe 修飾符對類型或成員沒有影響。在下面的示例中public class Apublic unsafe virtual void F() char* p;.public class B: Apublic override void F() base.F();.A 中 F 方法上的 unsafe 修飾符直接導(dǎo)致 F 的文本范圍成為不安全上下文并可以在其中使用語言的不安全功能。在 B 中對 F 的重寫中,不需要重新指定 unsafe 修飾符,除非 B 中的 F 方法本身需要訪問不安全功能。當(dāng)指針類型
9、是方法簽名的一部分時,情況略有不同public unsafe class Apublic virtual void F(char* p) .public class B: Apublic unsafe override void F(char* p) .此處,由于 F 的簽名包括指針類型,因此它只能出現(xiàn)在不安全上下文中。然而,為設(shè)置此不安全上下文,既可以將整個類設(shè)置為不安全的(如 A 中的情況),也可以僅在方法聲明中包含一個 unsafe 修飾符(如 B 中的情況)。1.2 指針類型在不安全上下文中,type(第 Error! Reference source not found. 章)可以是
10、 pointer-type,也可以是 value-type 或 reference-type。但是,pointer-type 也能在不安全上下文以外的 typeof 表達(dá)式(第 Error! Reference source not found. 節(jié))中使用,因為此類使用不是不安全的。type:value-typereference-typepointer-typepointer-type 可表示為 unmanaged-type 后跟一個 * 標(biāo)記,或者關(guān)鍵字 void 后跟一個 * 標(biāo)記:pointer-type:unmanaged-type *void *unmanaged-type:ty
11、pe指針類型中,在 * 前面指定的類型稱為該指針類型的目標(biāo)類型 (referent type)。它表示該指針類型的值所指向的變量的類型。與引用(引用類型的值)不同,指針不受垃圾回收器跟蹤(垃圾回收器并不知曉指針和它們指向的數(shù)據(jù))。出于此原因,不允許指針指向引用或者包含引用的結(jié)構(gòu),并且指針的目標(biāo)類型必須是 unmanaged-type。unmanaged-type 是任何不是 reference-type 并且在任何嵌套級別都不包含 reference-type 字段的類型。換句話說,unmanaged-type 是下列類型之一: sbyte、byte、short、ushort、int、uint
12、、long、ulong、char、float、double、decimal 或 bool。 任何 enum-type。 任何 pointer-type。 任何由用戶定義的只包含 unmanaged-type 字段的 struct-type。將指針和引用進(jìn)行混合使用時的基本規(guī)則是;引用(對象)的目標(biāo)可以包含指針,但指針的目標(biāo)不能包含引用。下表給出了一些指針類型的示例:示例說明byte*指向 byte 的指針char*指向 char 的指針int*指向 int 的指針的指針int*一維數(shù)組,它的元素是指向 int 的指針void*指向未知類型的指針對于某個給定實(shí)現(xiàn),所有的指針類型都必須具有相同的大
13、小和表示形式。與 C 和 C+ 不同,在 C# 中,當(dāng)在同一聲明中聲明多個指針時,* 只與基礎(chǔ)類型寫在一起,而不充當(dāng)每個指針名稱的前綴標(biāo)點(diǎn)符號。例如int* pi, pj;/ NOT as int *pi, *pj;類型為 T* 的一個指針的值表示類型為 T 的一個變量的地址。指針間接尋址運(yùn)算符 * (第 1.5.1 節(jié)) 可用于訪問此變量。例如,給定int* 類型的變量 P,則表達(dá)式 *P 表示 int 變量,該變量的地址就是 P 的值。 與對象引用類似,指針可以是 null。如果將間接尋址運(yùn)算符應(yīng)用于 null 指針,則其行為將由實(shí)現(xiàn)自己定義。值為 null 的指針表示為將該指針的所有位都
14、置零。void* 類型表示指向未知類型的指針。因為目標(biāo)類型是未知的,所以間接尋址運(yùn)算符不能應(yīng)用于 void* 類型的指針,也不能對這樣的指針執(zhí)行任何算術(shù)運(yùn)算。但是,void* 類型的指針可以強(qiáng)制轉(zhuǎn)換為任何其他指針類型(反之亦然)。指針類型是一個單獨(dú)類別的類型。與引用類型和值類型不同,指針類型不從 object 繼承,而且不存在指針類型和 object 之間的轉(zhuǎn)換。具體而言,指針不支持裝箱和拆箱(第 Error! Reference source not found. 節(jié))操作。但是,允許在不同指針類型之間以及指針類型與整型之間進(jìn)行轉(zhuǎn)換。在第 1.4 節(jié)中對此進(jìn)行了描述。pointer-type
15、 可用作易失字段的類型(第 Error! Reference source not found. 節(jié))。雖然指針可以作為 ref 或 out 參數(shù)傳遞,但這樣做可能會導(dǎo)致未定義的行為,例如,指針可能被設(shè)置為指向一個局部變量,而當(dāng)調(diào)用方法返回時,該局部變量可能已不存在了;或者指針曾指向一個固定對象,但當(dāng)調(diào)用方法返回時,該對象不再是固定的了。例如: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方法可以返回某一類型的值,而該類型可以是指針。例如,給定一個指向連續(xù)的 int 值序列的指針、該序列的元素個數(shù),和另外一個 int 值 (value),下面的方法將在該整數(shù)序列中查找與該 value 匹配的值,若找到匹配項,則返回該匹配項的地址;否則,它
17、將返回 null:unsafe static int* Find(int* pi, int size, int value) for (int i = 0; i 運(yù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 語句可用于臨時固定一個變量,以便可以獲取它的地址(第 1.6 節(jié))。1.3 固定和可移動變量address-of 運(yùn)算符(第 1.5.4 節(jié))和 fixed 語句(第 18.6 節(jié))將變量劃分為兩個類別:固定變量 (fixed variable) 和可移動變量 (moveable variable)。固定變量駐留在不受垃圾回收器的操作影響的存儲位置中。(固定變量的示例包括局部變量、值參數(shù)和由取消指針引用而創(chuàng)建的變量。)另一方面,可移動變量則駐留在會被垃圾回收器重定位或處置的存儲位置中。(可移動變量的示例包括對象中的字段和數(shù)組的元素。)& 運(yùn)算符(第 1.5.4 節(jié))允許不受限制地獲取固定變
19、量的地址。但是,由于可移動變量會受到垃圾回收器的重定位或處置,因此可移動變量的地址只能使用 fixed 語句(第 1.6 節(jié))獲取,而且該地址只在此 fixed 語句的生存期內(nèi)有效。準(zhǔn)確地說,固定變量是下列之一: 用引用局部變量或值參數(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é))表示的變量。所有其他變量都屬于可移動變量。請注意靜態(tài)字段屬于可移動變量。還請注意即使賦予 ref 或 out 形參的實(shí)參是固定變量,它們?nèi)詫儆诳梢苿幼兞?。最后請注意,由取消指針引用而產(chǎn)生的變量總是屬于固定變量。1.4 指針轉(zhuǎn)換在不安全上下文中,可供使用的隱式轉(zhuǎn)換的集合(第 Error! Reference source not found. 節(jié))也擴(kuò)展為包括以下隱式指針轉(zhuǎn)換: 從任何 pointer-type
21、 到 void* 類型。 從 null 類型到任何 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* 類型。兩個指針類型之間的轉(zhuǎn)換永遠(yuǎn)不會更改實(shí)際的指針值。換句話說,從一個指針類型到另一個指針類型的轉(zhuǎn)換不會影響由指針給出的基礎(chǔ)地址。當(dāng)一個指針類型被轉(zhuǎn)換為另一個指針類型時,如果沒有將得到的指針正確地對指向的類型對齊,則當(dāng)結(jié)果被取消引用時,該行為將是未定義的。一般情況下,“正確對齊”的概念是可傳遞的:如果指向類型 A 的指針正確地與指向類型 B 的指針對齊,而此指向類型 B 的指針又正確地與指向類型 C 的指針對齊,則指向類型 A 的
23、指針將正確地與指向類型 C 的指針對齊。請考慮下列情況,其中具有一個類型的變量被通過指向一個不同類型的指針訪問:char c = A;char* pc = &c;void* pv = pc;int* pi = (int*)pv;int i = *pi;/ undefined*pi = 123456;/ undefined當(dāng)一個指針類型被轉(zhuǎn)換為指向字節(jié)的指針時,轉(zhuǎn)換后的指針將指向原來所指變量的地址中的最低尋址字節(jié)。連續(xù)增加該變換后的指針(最大可達(dá)到該變量所占內(nèi)存空間的大?。?,將產(chǎn)生指向該變量的其他字節(jié)的指針。例如,下列方法將 double 型變量中的八個字節(jié)的每一個顯示為一個十六進(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)記,最后是一個 identifier。pointer-member-access:primary-expression - identifier在 P-I 形式的指針成員訪問中,P 必須是除 void* 以外的某個指針類型的表達(dá)式,而 I 必須表示 P 所指向的類型的可訪問成員。P-I 形式的指針成員訪問的計算方式與 (*P).I 完全相同。有關(guān)指針間接尋址運(yùn)算符 (
25、*) 的說明,請參見第 1.5.1 節(jié)。有關(guān)成員訪問運(yù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)算符用于通過指針訪問結(jié)構(gòu)中的字段和調(diào)用結(jié)構(gòu)中的方法。由于 P-I 操作完全等效于 (*P).I,因此 Main 方法可以等效地編寫為:class Teststatic void Main() Point point;unsafe Point* p = &point;(*p).x = 10;(*p).y = 20;Console.WriteLine(*p).ToString();1.5.3 指針元素訪問pointer-element-access 包括一個 primary-no-array-creation-expression,后跟一個用“”和“”括起來的表達(dá)式。
27、pointer-element-access:primary-no-array-creation-expression expression 在 PE 形式的指針元素訪問中,P 必須是 void* 以外的指針類型的表達(dá)式,而 E 則必須是可以隱式轉(zhuǎn)換為 int、uint、long 或 ulong 的類型的表達(dá)式。PE 形式的指針元素訪問的計算方式與 *(P + E) 完全相同。有關(guān)指針間接尋址運(yùn)算符 (*) 的說明,請參見第 1.5.1 節(jié)。有關(guān)指針加法運(yù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;指針元素訪問用于在 for 循環(huán)中初始化字符緩沖區(qū)。由于 PE 操作完全等效于 *(P + E),因此示例可以等效地編寫為:class Teststatic void Main() unsafe char* p = stackalloc char256;for (int i = 0; i 256; i+) *(p + i) = (char)i;指針元素訪問運(yùn)算符不能檢驗是否發(fā)生訪問越界錯誤,而且當(dāng)訪問超出邊界的元素時行為是未定義的。這與 C 和 C+ 相同。1.5
29、.4 address-of 運(yùn)算符addressof-expression 包含一個“and”符 (&),后跟一個 unary-expression。addressof-expression:& unary-expression如果給定類型為 T 且屬于固定變量(第 1.3 節(jié))的表達(dá)式 E,構(gòu)造 &E 將計算由 E 給出的變量的地址。計算的結(jié)果是一個類型為 T* 的值。如果 E 不屬于變量,如果 E 屬于只讀局部變量,或如果 E 表示可移的變量,則將發(fā)生編譯時錯誤。在最后一種情況中,可以先利用固定語句(第 1.6 節(jié))臨時“固定”該變量,再獲取它的地址。如第 Error! Reference
30、 source not found. 節(jié)中所述,如果在實(shí)例構(gòu)造函數(shù)或靜態(tài)構(gòu)造函數(shù)之外,在結(jié)構(gòu)或類中定義了 readonly 字段,則該字段被認(rèn)為是一個值,而不是變量。因此,無法獲取它的地址。與此類似,無法獲取常量的地址。& 運(yùn)算符不要求它的參數(shù)先被明確賦值,但是在執(zhí)行了 & 操作后,該運(yùn)算符所應(yīng)用于的那個變量在此操作發(fā)生的執(zhí)行路徑中被“認(rèn)為是”已經(jīng)明確賦值的。這意味著,由程序員負(fù)責(zé)確保在相關(guān)的上下文中對該變量實(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)為是明確賦值的。對 *p 的賦值實(shí)際上是初始化了 i,但設(shè)置此初始化是程序員的責(zé)任,而且如果移除此賦值語句,也不會發(fā)生編譯時錯誤。上述 & 運(yùn)算符的明確賦值規(guī)則可以避免局部變量的冗余初始化。例如,許多外部 API 要求獲取指向結(jié)構(gòu)的指針,而由此 API 來填充該結(jié)構(gòu)。對此類 API 進(jìn)行的調(diào)用通常會傳遞局部結(jié)構(gòu)變量的地址,而如果沒有上述規(guī)則,則將需要對此結(jié)構(gòu)變量進(jìn)行冗余初始化。1.5.5 指針遞增和遞減在不安全上下文中,+ 和 - 運(yùn)算符(第 Error! Reference source not f
32、ound. 節(jié)和第 節(jié))可以應(yīng)用于除 void* 以外的所有類型的指針變量。因此,為每個指針類型 T* 都隱式定義了下列運(yùn)算符:T* operator +(T* x);T* operator -(T* x);這些運(yùn)算符分別產(chǎn)生與 x + 1 和 x - 1(第 1.5.6 節(jié))相同的結(jié)果。換句話說,對于 T* 類型的指針變量,+ 運(yùn)算符將該變量的地址加上 sizeof(T),而 - 運(yùn)算符則將該變量的地址減去 sizeof(T)。如果指針遞增或遞減運(yùn)算的結(jié)果超過指針類型的域,則結(jié)果是由實(shí)現(xiàn)定義的,但不會產(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* 以外的所有指針類型的值。因此,為每個指針類型 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);給定指針類型 T* 的表達(dá)式 P 和類型 int、uint、long 或 ulong 的表達(dá)式 N,表達(dá)式 P + N 和 N + P 的計算結(jié)果是一個屬于類型 T* 的指針值,該值等于由 P 給出的地址加上 N * sizeof(T)。與此類似,表達(dá)式 P - N 的計算結(jié)果也是一個屬于類型 T* 的指針值,該
35、值等于由 P 給出的地址減去 N * sizeof(T)。給定指針類型 T* 的兩個表達(dá)式 P 和 Q,表達(dá)式 P Q 將先計算 P 和 Q 給出的地址之間的差,然后用 sizeof(T) 去除該差值。計算結(jié)果的類型始終為 long。實(shí)際上,P - Q 的計算過程是:(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,計算結(jié)果超越該指針類型的域,則將以實(shí)現(xiàn)所定義的方式截斷結(jié)果,但是不會產(chǎn)生異常。1.5.7 指針比較在不安全上下文中,=、!=、 運(yùn)算符(第 Error! Reference source not found. 節(jié))可以應(yīng)用于所有指針類型的值。指針比較運(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);由于存在從任何指針類型到 void* 類型的隱式轉(zhuǎn)換,因此可以使用這些運(yùn)算符來比較任何指針類型的操作數(shù)。比較運(yùn)算符像比較無符號整數(shù)一樣比較兩個操作數(shù)給出的地址。1.5.8 sizeof 運(yùn)算符sizeof 運(yùn)算符返回由給定類型的變量占用的字節(jié)數(shù)。被指定為 sizeof 的操作數(shù)的類型必須為 unmanaged-type(第 1.2 節(jié))。sizeof-expression:sizeof ( unmanaged-type )sizeof 運(yùn)算符的結(jié)果是 int 類
38、型的值。對于某些預(yù)定義類型,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對于所有其他類型,sizeof 運(yùn)算符的結(jié)果是由實(shí)現(xiàn)定義的,并且屬于值而不是常量。一個結(jié)構(gòu)所屬的各個成員以什么順序被裝入該結(jié)構(gòu)中,沒有明確規(guī)定。出于對齊的目的,在結(jié)構(gòu)的開頭、結(jié)構(gòu)內(nèi)以及結(jié)構(gòu)的
39、結(jié)尾處可以插入一些未命名的填充位。這些填充位的內(nèi)容是不確定的。當(dāng) sizeof 應(yīng)用于具有結(jié)構(gòu)類型的操作數(shù)時,結(jié)果是該類型變量所占的字節(jié)總數(shù)(包括所有填充位在內(nèi))。1.6 fixed 語句在不安全上下文中,embedded-statement(第 Error! Reference source not found. 章)產(chǎn)生式允許使用一個附加結(jié)構(gòu)即 fixed 語句,該語句用于“固定”可移動變量,從而使該變量的地址在語句的持續(xù)時間內(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)生式所述,每個 fixed-pointer-declarator 聲
41、明一個給定 pointer-type 的局部變量,并使用由相應(yīng)的 fixed-pointer-initializer 計算的地址初始化該局部變量。在 fixed 語句中聲明的局部變量的可訪問范圍僅限于:在該變量聲明右邊的所有 fixed-pointer-initializer 中,以及在該 fixed 語句的 embedded-statement 中。由 fixed 語句聲明的局部變量被視為只讀。如果嵌入語句試圖修改此局部變量(通過賦值或 + 和 - 運(yùn)算符)或者將它作為 ref 或 out 參數(shù)傳遞,則將出現(xiàn)編譯時錯誤。fixed-pointer-initializer 可以是下列之一: “
42、&”標(biāo)記,后跟一個 variable-reference(第 Error! Reference source not found. 節(jié)),它引用非托管類型 T 的可移動變量(第 18.3 節(jié)),前提是類型 T* 可以隱式轉(zhuǎn)換為 fixed 語句中給出的指針類型。在這種情況下,初始值設(shè)定項將計算給定變量的地址,而 fixed 語句在生存期內(nèi)將保證該變量的地址不變。 元素類型為非托管類型 T 的 array-type 的表達(dá)式,前提是類型 T* 可隱式轉(zhuǎn)換為 fixed 語句中給出的指針類型。在這種情況下,初始值設(shè)定項將計算數(shù)組中第一個元素的地址,而 fixed 語句在生存期內(nèi)將保證整個數(shù)組的地址
43、保持不變。如果數(shù)組表達(dá)式為 null 或者數(shù)組具有零個元素,則 fixed 語句的行為由實(shí)現(xiàn)定義。 string 類型的表達(dá)式,前提是類型 char* 可以隱式轉(zhuǎn)換為 fixed 語句中給出的指針類型。在這種情況下,初始值設(shè)定項將計算字符串中第一個字符的地址,而 fixed 語句在生存期內(nèi)將保證整個字符串的地址不變。如果字符串表達(dá)式為 null,則 fixed 語句的行為由實(shí)現(xiàn)定義。對于每個由 fixed-pointer-initializer 計算的地址,fixed 語句確保由該地址引用的變量在 fixed 語句的生存期內(nèi)不會被垃圾回收器重定位或者處置。例如,如果由 fixed-pointer-initializer 計算的地址引用對象的字段或數(shù)組實(shí)例的元素,fixed 語句將保證包含該字段或元素的對象實(shí)例本身也不會在該語句的生存期內(nèi)被重定位或者處置。確保由 fixed 語句創(chuàng)建的指針在執(zhí)行這些語句之后不再存在是程序員的責(zé)任。例如,當(dāng) fixed 語句創(chuàng)建的指針被傳遞到外部 API 時,確保 API 不會在內(nèi)存中保留這些指針是程序員的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 計算機(jī)操作工??荚囶}與答案
- 用電客戶受理員練習(xí)題+答案
- 車工高級工練習(xí)題庫及答案
- 山東省濟(jì)寧市鄒城市2024-2025學(xué)年高二下學(xué)期4月期中生物試題 (原卷版+解析版)
- 航空器維修工程中的技術(shù)創(chuàng)新與轉(zhuǎn)化考核試卷
- 水果和堅果加工的食品安全與質(zhì)量控制考核試卷
- 石棉材料的斷裂性能測試考核試卷
- 涂料門店銷售數(shù)據(jù)化管理考核試卷
- 筆的制造業(yè)商業(yè)模式創(chuàng)新與案例分析考核試卷
- 煙草制品零售企業(yè)盈利模式分析考核試卷
- 黃金白銀投資寶典:一本書學(xué)會貴金屬投資
- 建筑施工高處作業(yè)安全帶系掛點(diǎn)圖集(2023年)
- 華中師大《心理測量學(xué)》復(fù)習(xí)題庫及答案
- 工作秘密事項清單范文(6篇)
- 醫(yī)院醫(yī)學(xué)影像科CT-MR室診療指南和操作規(guī)范2022版
- “雙減”政策背景下小學(xué)生籃球運(yùn)動發(fā)展 論文
- 公司基本情況介紹
- 肝移植并發(fā)癥膽道并發(fā)癥
- 異步電機(jī)矢量控制系統(tǒng)設(shè)計
- GB/T 39529-2020系統(tǒng)門窗通用技術(shù)條件
- GB/T 29602-2013固體飲料
評論
0/150
提交評論