淺談C#固定的和活動(dòng)的變量
C#固定的和活動(dòng)的變量
&和fixed將變量分為兩類:C#固定的和活動(dòng)的變量。
固定的變量***的存在并不會(huì)被GC的操作影響。(例如局部變量,值參數(shù)和間接指針)活動(dòng)的變量會(huì)被GC重新分配位置或是釋放(例如對(duì)象中的字段,基礎(chǔ)數(shù)據(jù)數(shù)組)。
&取固定變量的地址是沒有限制的。但是活動(dòng)變量容易受GC的影響,其地址只能通過fixed來獲得,并且地址僅會(huì)在整個(gè)fixed語(yǔ)句的周期持續(xù)有效。
靜態(tài)字段也是活動(dòng)變量。還有標(biāo)記為ref或out的也是活動(dòng)變量,即使這個(gè)參數(shù)是傳遞給固定參數(shù)的。***,通過間接指針引用的變量總是固定變量。
指針轉(zhuǎn)換
在不安全上下文中,下面的轉(zhuǎn)換是隱式的:
◆從任何指針類型到void*
◆從null到任何指針類型
除此之外,下面的轉(zhuǎn)換都是顯式的:
◆從任何指針類型到另外的指針類型
◆從sbyte, byte, short, ushort, int, uint, long, or ulong到其他類型
◆從任何類型到sbyte, byte, short, ushort, int, uint, long, or ulong
指針轉(zhuǎn)換并不改變指針的值。也就是說指針轉(zhuǎn)換前后不影響地址的值。
當(dāng)轉(zhuǎn)換發(fā)生后,當(dāng)結(jié)果指針沒有按照正確的指針類型排列的話,當(dāng)訪問結(jié)果時(shí)結(jié)果是無法預(yù)知的。
下面的例子:
- char c = 'A';
- char* pc = &c;
- void* pv = pc;
- int* pi = (int*)pv;
- int i = *pi;
- // undefined
- *pi = 123456;
- // undefined
下面的例子會(huì)打印出double的8字節(jié)的值:
- usingSystem;
- classTest
- {
- unsafestaticvoidMain(){
- doubled=123.456e23;
- unsafe{
- byte*pb=(byte*)&d;
- for(inti=0;i<sizeof(double);++i)
- Console.Write("{0:X2}",*pb++);
- Console.WriteLine();
- }
- }
- }
打印結(jié)果取決于endian.
指針數(shù)組
在不安全上下文中,是允許指針數(shù)組的,只有幾種用于其轉(zhuǎn)換是允許的:
◆從任何數(shù)組類型到System.Array或是實(shí)現(xiàn)了其接口的隱式引用類型轉(zhuǎn)換同樣適用于指針數(shù)組。但是,任何試圖通過System.Array或是實(shí)現(xiàn)了其接口訪問數(shù)組元素都會(huì)引發(fā)一個(gè) 運(yùn)行時(shí)錯(cuò)誤,因?yàn)橹羔橆愋筒荒苻D(zhuǎn)化為object.
◆從一個(gè)一維數(shù)組類型S[]到System.Collections.Generic.IList<T>或是到其基接口,任何顯示或是隱式的轉(zhuǎn)換都是不行的。因?yàn)橹羔橆愋筒荒鼙挥米黝愋蛥?shù),還有沒有從指針類型到非指針類型的轉(zhuǎn)換。
◆從System.Array或是實(shí)現(xiàn)了其接口到任何數(shù)組類型顯示引用轉(zhuǎn)換適用于指針數(shù)組。
◆從System.Collections.Generic.IList<T>或是到其基接口到一個(gè)一維數(shù)組類型T[],任何顯示的轉(zhuǎn)換都是不行的。原因同上面第2條。
還有就是對(duì)于foreach語(yǔ)句,不適用于指針數(shù)組。相反,下面的語(yǔ)句
foreach (V v in x) embedded-statement
中的x是一個(gè)數(shù)組類型T[,,…,],n是數(shù)組的維度減1,T和V是指針類型,被改寫為:
- {
- T[,,…,]a=x;
- Vv;
- for(inti0=a.GetLowerBound(0);i0<=a.GetUpperBound(0);i0++)
- for(inti1=a.GetLowerBound(1);i1<=a.GetUpperBound(1);i1++)
- …
- for(intin=a.GetLowerBound(n);in<=a.GetUpperBound(n);in++){
- v=(V)a.GetValue(i0,i1,…,in);
- embedded-statement
- }
- }
變量a,i0,i1,…對(duì)于x或者embedded-statement或者其余部分的代碼是不可見的或是不可訪問的。變量v在embedded-statement中是只讀的。如果沒有顯示轉(zhuǎn)換從T到V,那么就會(huì)有錯(cuò)誤。如果x是個(gè)null,就會(huì)有空引用異常。
表達(dá)式中的指針
在不安全上下文中,一個(gè)表達(dá)式的值可以來自于一個(gè)指針類型;但是在上下文之外,會(huì)造成編譯時(shí)期錯(cuò)誤。
間接訪問
一元的*表示一個(gè)指針,被用來獲得指針指向的值。*用在void*類型表達(dá)式或是非指針類型表達(dá)式時(shí),會(huì)造成編譯期錯(cuò)誤。
*被用在null指針時(shí)是由實(shí)現(xiàn)來決定的。不能保證在使用時(shí)會(huì)拋出System.NullReferenceException.
如果一個(gè)非法的值賦給指針,那么*的行為是不可預(yù)知的。
指針成員訪問
在指針成員訪問P->I中,P必須是除了void*之外的類型,I同時(shí)必須是一個(gè)可訪問的成員。
P->I效果上相同于(*P)。I.例如:
- usingSystem;
- structPoint
- {
- publicintx;
- publicinty;
- publicoverridestringToString(){
- return"("+x+","+y+")";
- }
- }
- classTest
- {
- staticvoidMain(){
- Pointpoint;
- unsafe{
- Point*p=&point;
- p->x=10;
- p->y=20;
- Console.WriteLine(p->ToString());
- }
- }
- }
或是
- classTest
- {
- staticvoidMain(){
- Pointpoint;
- unsafe{
- Point*p=&point;
- (*p).x=10;
- (*p).y=20;
- Console.WriteLine((*p).ToString());
- }
- }
- }
指針元素訪問
在指針元素訪問P[E]中,P必須是除了void*之外的類型,同時(shí)E必須能隱式的轉(zhuǎn)換為int, uint, long, or ulong的表達(dá)式。
P[E]效果上同*(P + E)。例如:
- classTest
- {
- staticvoidMain(){
- unsafe{
- char*p=stackallocchar[256];
- for(inti=0;i<256;i++)p[i]=(char)i;
- }
- }
- }
- 又如:
- classTest
- {
- staticvoidMain(){
- unsafe{
- char*p=stackallocchar[256];
- for(inti=0;i<256;i++)*(p+i)=(char)i;
- }
- }
- }
以上介紹C#固定的和活動(dòng)的變量
【編輯推薦】