成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳細介紹C#編譯器

開發 后端
本文介紹C#編譯器,以及介紹無論你在哪個范圍,在什么時候開始聲明,實際上都是在函數的一開始用一個.locals這樣的偽語句來聲明的。

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

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

在這個Test函數里面有兩對打括號,標明兩個互不相屬的子范圍。這里大家也許看的非常不習慣,因為沒有人光禿禿的寫這么兩對大括號的。我跟大家說:沒關系,編譯器承認光禿禿的大括號的,這個也是標準C里面的規范之一,作用就是把大括號里面的所有東西認為是“一句話”,準確點講是邏輯語句,同時內部是一個范圍,約束范圍內的本地變量不會往外傳播。如果大家實在看不習慣了,可以自行加上諸如while(true)之類的前綴,就習慣了。

那么這段代碼有什么Bug呢?沒有,確實沒有Bug,編譯順利通過。當然,顯示了兩個Warning,說a沒有被用到,無傷大雅。我們首先來分析一下,編譯器怎么給把這個給弄通過的呢?我們用Reflector來看一下(當然,因為沒有切實的代碼,所以只能夠看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. }  

哦!原來編譯器把內部的變量改名字了!或者說編譯器把他們當作完全不同的兩個變量來對待。同時我們在這里也可以看出來,實際上在IL里面時不區分范圍的,只有本地變量著一個簡單的概念。無論你在哪個范圍,在什么時候開始聲明,實際上都是在函數的一開始用一個.locals這樣的偽語句來聲明的。這么做是簡單省事的辦法,因為如果在用戶源代碼實際聲明的地方才在棧上面開辟空間,那么最后函數退出的時候就不知道該釋放多少棧空間了。當然這不是不可以解決的,但是那樣的話增加了不必要的復雜度。如果我來設計.NET Framework,我也會通過高級語言的編譯器來約束范圍問題,而不是擺到IL里面去解決。(畢竟IL里面沒有這樣的功能不影響我們寫程序)稍微引申一下,我們就知道,一個函數里面有多少個本地變量,取決于整個函數內部聲明了多少本地變量,而與變量所在范圍無關。在IL這一層里面暫時我們沒有看到這樣的優化工作,我們可以看看這樣的代碼最后被編譯器編譯成什么了(用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 反編譯結果:

  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則是分別的兩個a。事實上這兩個a互相之間是沒有任何沖突的,也就是說是完全可以重用的,編譯原理里面也有一個變量重用的優化,但是這里看不到有這樣的優化,我覺得比較吃驚。雖然說這也可以算是一種Bug(嚴格說來是也不是),但是我要說的“Bug”不是這個。

分析完上面這些基本知識,我就來勁了:

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

看,編譯出來之后卻出現了錯誤:
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
哦,原來這個跟聲明的順序還沒有關系,只要子范圍里面有a了,那就不能夠再定義這個變量了。這個難道跟IL里面所有變量都在函數開始部分聲明有關系?看起來好像是這么一回事,但是實際上不是,因為C#編譯器完全可以像前面那樣,把最后一個a當作另外一個變量。這到底是怎么回事呢?我們需要作本次探索的最后一個實驗:

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

這下可好,除了剛才那個錯誤之外,還多出來另外一個:
error CS0103: The name 'a' does not exist in the class or namespace 'ConsoleApplication1.Class2'
也就是說,編譯器根本就沒有把后面那個a當作從函數一開始的地方定義來看待。但是這兩個錯誤合起來反而容易讓我們產生這樣的錯覺和悖論:
因為前面兩個a在范圍外面就應該消失其影響力,那就不應該跟后面的a產生沖突。但現在既然你說了,第三個a的定義根前面那兩個a的其中某一個定義相沖突了,那我就只能夠認為后面這個a實際上在前兩個a被定義出來之前就已經存在了,因為后面這個a處于外層范圍,它不會在內層范圍失去作用之前失效,這樣還能夠解釋得通。可是這么解釋我只能夠認為外層的a應該在函數一開始的地方就生效了(老式的C編譯器有一段時間確實是這樣的),可是偏偏還來一個CS0103錯誤!解釋不通,有“Bug”!

最后我來修正這個我一開始提出的說法,其實并沒有Bug。得出有Bug的結論,那是從純粹的語法角度看這個問題的,我也覺得應該容許在第三個a的定義出現,頂多只給出一個Warning。但是微軟卻給出了一個錯誤,我想這是從避免不必要的Bug的角度考慮,盡量保護開發人員避免不必要的煩惱。開發人員確實很有可能在定義了第三個a的時候忘記第一二個a已經失效了,同時也忘記了自己定義過第三個a,還以為自己用的是第一個或者第二個a里面的數據。不過對于這種解釋,我還是有意見的:既然約束已經縮窄到這個地步了,那為什么要允許第二個a的定義呢?如果開發人員會忘記自己定義過第三個a,有什么理由認為不會把第二個a的定義給忘記了,以為自己在用第一個a呢?

本來上面所寫的那些統統都是垃圾代碼,我認為,在一個函數內部根本就不應該有相同的變量來迷惑自己。C#編譯器在這些問題方面確實有相當嚴謹的考慮,不過我還是覺得有一些“悖論”存在,如果能夠更加嚴謹,我認為只會更好。

責任編輯:佚名 來源: 天極開發
相關推薦

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-10 16:30:56

C# BitmapDa

2009-08-12 15:34:40

C# DBNull

2010-05-28 14:55:17

Linux編程工具

2009-08-07 16:10:20

C#調用API

2009-08-26 17:31:59

C# const常量

2009-08-03 18:49:17

C#和Java

2009-08-21 15:16:23

C#使用指針

2009-08-21 09:23:11

C# GDI+

2009-08-20 15:26:42

C#循環語句

2009-08-24 18:21:23

C# ListView

2009-08-14 17:04:50

C#類型系統

2009-08-13 13:38:30

C#命名規范

2009-12-24 10:04:38

Linux進行C編譯

2010-01-18 10:34:21

C++編譯器
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲成av片人久久久 | 午夜精品 | 国产成人午夜高潮毛片 | 精品视频免费在线 | 九九伦理片 | 在线欧美视频 | 国产成人a亚洲精品 | 国产亚洲一区二区三区在线观看 | 美女131mm久久爽爽免费 | 国产精品自拍啪啪 | 午夜在线免费观看视频 | 黄免费观看视频 | 久久精品亚洲精品国产欧美kt∨ | 伊色综合久久之综合久久 | 久久伦理中文字幕 | 精品视频网 | 久久av一区二区三区 | 日本超碰 | 亚洲福利av | 中文字幕日韩欧美 | 久久久久亚洲 | 欧美国产精品一区二区三区 | 欧美一区二区视频 | 日韩毛片免费看 | 成人精品一区二区 | 中文字幕亚洲精品 | 亚洲区一| www.久久 | 2019精品手机国产品在线 | 亚洲午夜三级 | 国产成人精品一区二区在线 | 久久久久国产 | 欧美精品一二三区 | 一区二区三区欧美大片 | 中文字幕二区 | av在线成人 | 日本高清中文字幕 | 国产精品亚洲欧美日韩一区在线 | 日韩欧美在线播放 | 国产日韩av一区二区 | 在线中文字幕第一页 |