自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

詳細(xì)介紹C#編譯器

開(kāi)發(fā) 后端
本文介紹C#編譯器,以及介紹無(wú)論你在哪個(gè)范圍,在什么時(shí)候開(kāi)始聲明,實(shí)際上都是在函數(shù)的一開(kāi)始用一個(gè).locals這樣的偽語(yǔ)句來(lái)聲明的。

本文講述C#編譯器的一些問(wèn)題,目的是防止錯(cuò)誤使用本地變量。但是據(jù)我研究,這里面有“Bug”(注意雙引號(hào)),那么會(huì)有什么有趣的“Bug”呢?首先大家看下一個(gè)簡(jiǎn)單的例子:

  1. publicvoidTest()  
  2. {  
  3. {  
  4. inta;  
  5. }  
  6. {  
  7. inta;  
  8. }  
  9. }  

在這個(gè)Test函數(shù)里面有兩對(duì)打括號(hào),標(biāo)明兩個(gè)互不相屬的子范圍。這里大家也許看的非常不習(xí)慣,因?yàn)闆](méi)有人光禿禿的寫(xiě)這么兩對(duì)大括號(hào)的。我跟大家說(shuō):沒(méi)關(guān)系,編譯器承認(rèn)光禿禿的大括號(hào)的,這個(gè)也是標(biāo)準(zhǔn)C里面的規(guī)范之一,作用就是把大括號(hào)里面的所有東西認(rèn)為是“一句話”,準(zhǔn)確點(diǎn)講是邏輯語(yǔ)句,同時(shí)內(nèi)部是一個(gè)范圍,約束范圍內(nèi)的本地變量不會(huì)往外傳播。如果大家實(shí)在看不習(xí)慣了,可以自行加上諸如while(true)之類(lèi)的前綴,就習(xí)慣了。

那么這段代碼有什么Bug呢?沒(méi)有,確實(shí)沒(méi)有Bug,編譯順利通過(guò)。當(dāng)然,顯示了兩個(gè)Warning,說(shuō)a沒(méi)有被用到,無(wú)傷大雅。我們首先來(lái)分析一下,編譯器怎么給把這個(gè)給弄通過(guò)的呢?我們用Reflector來(lái)看一下(當(dāng)然,因?yàn)闆](méi)有切實(shí)的代碼,所以只能夠看IL,而不能夠看C#):

  1. publichidebysiginstancevoidTest()cilmanaged  
  2. {  
  3. //CodeSize:2byte(s)  
  4. .maxstack0  
  5. .locals(  
  6. int32num1,  
  7. int32num2)  
  8. L_0000:nop  
  9. L_0001:ret  
  10. }  

哦!原來(lái)編譯器把內(nèi)部的變量改名字了!或者說(shuō)編譯器把他們當(dāng)作完全不同的兩個(gè)變量來(lái)對(duì)待。同時(shí)我們?cè)谶@里也可以看出來(lái),實(shí)際上在IL里面時(shí)不區(qū)分范圍的,只有本地變量著一個(gè)簡(jiǎn)單的概念。無(wú)論你在哪個(gè)范圍,在什么時(shí)候開(kāi)始聲明,實(shí)際上都是在函數(shù)的一開(kāi)始用一個(gè).locals這樣的偽語(yǔ)句來(lái)聲明的。這么做是簡(jiǎn)單省事的辦法,因?yàn)槿绻谟脩?hù)源代碼實(shí)際聲明的地方才在棧上面開(kāi)辟空間,那么最后函數(shù)退出的時(shí)候就不知道該釋放多少??臻g了。當(dāng)然這不是不可以解決的,但是那樣的話增加了不必要的復(fù)雜度。如果我來(lái)設(shè)計(jì).NET Framework,我也會(huì)通過(guò)高級(jí)語(yǔ)言的編譯器來(lái)約束范圍問(wèn)題,而不是擺到IL里面去解決。(畢竟IL里面沒(méi)有這樣的功能不影響我們寫(xiě)程序)稍微引申一下,我們就知道,一個(gè)函數(shù)里面有多少個(gè)本地變量,取決于整個(gè)函數(shù)內(nèi)部聲明了多少本地變量,而與變量所在范圍無(wú)關(guān)。在IL這一層里面暫時(shí)我們沒(méi)有看到這樣的優(yōu)化工作,我們可以看看這樣的代碼最后被編譯器編譯成什么了(用Release模式編譯):

  1. publicintTest()  
  2. {  
  3. intb;  
  4. b=newRandom().Next(5);  
  5. if(b<5)  
  6. {  
  7. inta=newRandom().Next(5);  
  8. Console.WriteLine(a);  
  9. b=a;  
  10. }  
  11. else  
  12. {  
  13. inta=newRandom().Next(10);  
  14. Console.WriteLine(a);  
  15. b=a;  
  16. }  
  17. returnb;  
  18. }  

Reflector 反編譯結(jié)果:

  1. publicintTest()  
  2. {  
  3. intnum1=newRandom().Next(5);  
  4. if(num1<5)  
  5. {  
  6. intnum2=newRandom().Next(5);  
  7. Console.WriteLine(num2);  
  8. returnnum2;  
  9. }  
  10. intnum3=newRandom().Next(10);  
  11. Console.WriteLine(num3);  
  12. returnnum3;  

大家可以看到num1是b,num2和num3則是分別的兩個(gè)a。事實(shí)上這兩個(gè)a互相之間是沒(méi)有任何沖突的,也就是說(shuō)是完全可以重用的,編譯原理里面也有一個(gè)變量重用的優(yōu)化,但是這里看不到有這樣的優(yōu)化,我覺(jué)得比較吃驚。雖然說(shuō)這也可以算是一種Bug(嚴(yán)格說(shuō)來(lái)是也不是),但是我要說(shuō)的“Bug”不是這個(gè)。

分析完上面這些基本知識(shí),我就來(lái)勁了:

  1. publicvoidTest()  
  2. {  
  3. {  
  4. inta;  
  5. }  
  6. {  
  7. inta;  
  8. }  
  9. inta;  

看,編譯出來(lái)之后卻出現(xiàn)了錯(cuò)誤:
error CS0136: A local variable named 'a' cannot be declared in this scope because it would give a different meaning to 'a', which is already used in a 'child' scope to denote something else
哦,原來(lái)這個(gè)跟聲明的順序還沒(méi)有關(guān)系,只要子范圍里面有a了,那就不能夠再定義這個(gè)變量了。這個(gè)難道跟IL里面所有變量都在函數(shù)開(kāi)始部分聲明有關(guān)系?看起來(lái)好像是這么一回事,但是實(shí)際上不是,因?yàn)镃#編譯器完全可以像前面那樣,把最后一個(gè)a當(dāng)作另外一個(gè)變量。這到底是怎么回事呢?我們需要作本次探索的最后一個(gè)實(shí)驗(yàn):

  1. publicvoidTest()  
  2. {  
  3. a=2;  
  4. {  
  5. inta;  
  6. }  
  7. {  
  8. inta;  
  9. }  
  10. inta;  

這下可好,除了剛才那個(gè)錯(cuò)誤之外,還多出來(lái)另外一個(gè):
error CS0103: The name 'a' does not exist in the class or namespace 'ConsoleApplication1.Class2'
也就是說(shuō),編譯器根本就沒(méi)有把后面那個(gè)a當(dāng)作從函數(shù)一開(kāi)始的地方定義來(lái)看待。但是這兩個(gè)錯(cuò)誤合起來(lái)反而容易讓我們產(chǎn)生這樣的錯(cuò)覺(jué)和悖論:
因?yàn)榍懊鎯蓚€(gè)a在范圍外面就應(yīng)該消失其影響力,那就不應(yīng)該跟后面的a產(chǎn)生沖突。但現(xiàn)在既然你說(shuō)了,第三個(gè)a的定義根前面那兩個(gè)a的其中某一個(gè)定義相沖突了,那我就只能夠認(rèn)為后面這個(gè)a實(shí)際上在前兩個(gè)a被定義出來(lái)之前就已經(jīng)存在了,因?yàn)楹竺孢@個(gè)a處于外層范圍,它不會(huì)在內(nèi)層范圍失去作用之前失效,這樣還能夠解釋得通??墒沁@么解釋我只能夠認(rèn)為外層的a應(yīng)該在函數(shù)一開(kāi)始的地方就生效了(老式的C編譯器有一段時(shí)間確實(shí)是這樣的),可是偏偏還來(lái)一個(gè)CS0103錯(cuò)誤!解釋不通,有“Bug”!

最后我來(lái)修正這個(gè)我一開(kāi)始提出的說(shuō)法,其實(shí)并沒(méi)有Bug。得出有Bug的結(jié)論,那是從純粹的語(yǔ)法角度看這個(gè)問(wèn)題的,我也覺(jué)得應(yīng)該容許在第三個(gè)a的定義出現(xiàn),頂多只給出一個(gè)Warning。但是微軟卻給出了一個(gè)錯(cuò)誤,我想這是從避免不必要的Bug的角度考慮,盡量保護(hù)開(kāi)發(fā)人員避免不必要的煩惱。開(kāi)發(fā)人員確實(shí)很有可能在定義了第三個(gè)a的時(shí)候忘記第一二個(gè)a已經(jīng)失效了,同時(shí)也忘記了自己定義過(guò)第三個(gè)a,還以為自己用的是第一個(gè)或者第二個(gè)a里面的數(shù)據(jù)。不過(guò)對(duì)于這種解釋?zhuān)疫€是有意見(jiàn)的:既然約束已經(jīng)縮窄到這個(gè)地步了,那為什么要允許第二個(gè)a的定義呢?如果開(kāi)發(fā)人員會(huì)忘記自己定義過(guò)第三個(gè)a,有什么理由認(rèn)為不會(huì)把第二個(gè)a的定義給忘記了,以為自己在用第一個(gè)a呢?

本來(lái)上面所寫(xiě)的那些統(tǒng)統(tǒng)都是垃圾代碼,我認(rèn)為,在一個(gè)函數(shù)內(nèi)部根本就不應(yīng)該有相同的變量來(lái)迷惑自己。C#編譯器在這些問(wèn)題方面確實(shí)有相當(dāng)嚴(yán)謹(jǐn)?shù)目紤],不過(guò)我還是覺(jué)得有一些“悖論”存在,如果能夠更加嚴(yán)謹(jǐn),我認(rèn)為只會(huì)更好。

責(zé)任編輯:佚名 來(lái)源: 天極開(kāi)發(fā)
相關(guān)推薦

2009-08-14 11:34:26

Mono C#編譯器

2009-09-01 10:35:19

C# 3.0編譯器

2009-08-10 17:12:54

C#編譯器

2009-08-18 11:27:56

配置C#命令行編譯器

2009-08-14 16:37:02

C# NGWS run

2010-01-21 09:26:53

CC++編譯器

2009-08-12 15:34:40

C# DBNull

2009-08-10 16:30:56

C# BitmapDa

2010-05-28 14:55:17

Linux編程工具

2009-08-14 17:04:50

C#類(lèi)型系統(tǒng)

2009-08-13 13:38:30

C#命名規(guī)范

2009-08-03 18:49:17

C#和Java

2009-08-07 16:10:20

C#調(diào)用API

2009-08-20 15:26:42

C#循環(huán)語(yǔ)句

2009-08-21 15:16:23

C#使用指針

2009-08-24 18:21:23

C# ListView

2009-08-26 17:31:59

C# const常量

2009-08-21 09:23:11

C# GDI+

2009-12-24 10:04:38

Linux進(jìn)行C編譯

2010-01-18 10:34:21

C++編譯器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)