當前位置:首頁 » 編程軟體 » 編譯器細節

編譯器細節

發布時間: 2022-10-11 08:45:31

① 關於c語言的一些細節問題

語義錯誤指的是邏輯上的錯誤,像是你在使用一個變數之前沒有聲明,不是格式上的錯誤

語法錯誤是格式上的錯誤,比如一個語句最後沒有加分號

有的編譯器沒有語義分析程序,所以你編譯時即使語義上有錯誤,也不會報錯,只有當運行時才會錯誤
所有的編譯器都有語法分析程序(理論上是這么說,自己寫個編譯器當然可以不帶)

② 開發一個 C++ 編譯器的難度有多大,難點又在哪裡

C++的前端是出了名的復雜度和可靠性要求並駕齊驅的軟體。

(這兩點都比它高一個數量級的大概就只有OS了)

對於這種系統,唯一的辦法就是燒錢。

燒錢的作用主要包括:
1.留人;
2.填坑;
3.買買買。

先說留人:復雜度一般是「細節」的代名詞。現實中的編譯器大多數以遞歸下降為主,自底向上的歸納推導為輔。這兩樣在教科書上也就是幾頁紙的事情。但是現實總是很殘酷的,人們總想讓語言更加「易用」,這就意味著各種上下文相關的情況都會出現。

對於C++來說,你要判斷一個符號是類型或者變數(比如這個符號被用在模板參數中),要看前面的聲明/定義。這就是一個上下文相關的推導。然後你就會寫大量的if else switch case之類的代碼來解決各種各樣的可能分支。寫它的人當然知道它是做什麼的,但是如果這個人離職了,新來一個人,就呆掉了,這寫的都是什麼煞筆玩意兒。因為它不知道現實中怎樣的需求會導致奇形怪狀的邏輯。所以人員的穩定,對於這種長周期迭代、邏輯復雜的項目是很重要的。但是人的水平要求高嗎?不算高也不算低。總結來說就是:有邏輯,知好歹。技術什麼都可以培養,但是態度和基本智商是比較難培養起來的。

至於怎麼保證人員穩定?很簡單:加薪。

再說填坑:編譯器是對正確性要求很高的基礎軟體。這里的正確性既包括產生的代碼的正確性,也包括編譯器自身對於各種問題的容忍度和足夠豐富的錯誤提示。容錯和錯誤提示本身也是代碼,也有很大的出錯幾率。所以這些軟體,bug少不了。但是作為基礎軟體,你又不能隨便就2+3搞成了2*3,這樣還怎麼讓別人相信愛情。所以要燒很多錢來養一幫debugger。

再說買買買:古人日:我們不用很麻煩很辛苦也可以成佛。既然這么費神我們自己做干什麼,不如買別人的吧。於是MS就乾脆不自己做了,直接去EDG整了個前端,這樣就可以少了不少人年。這就是傳統土豪和水果這種新暴發戶想的不一樣的地方。

傳統土豪想的是:我們有這么多錢為什麼還要自己解決問題呢?買買買!
水果新貴則是:啊呀,不小心有了這么多錢,我們要不要給自己製造點問題好把這些錢花出去?

③ C語言編譯器如何下載

在Code::Blocks官網上下載帶mingw組件的Code::Blocks(一定要帶有mingw,否則就沒有編譯器可用),安裝,然後就可以用Code::Blocks編寫代碼和編譯運行了。如何使用CB可以自己搜網上教程。

④ 哪位大牛能告訴我,c語言中的'&'這個符號,到底編譯器是怎麼識別並運用它的

'&'是多功能運算符,至於如何解釋該符號,編譯器是根據「上下文」來判斷的。
由於在C中每個變數必須先聲明後使用,比如有聲明 :
int x = 3,y = 5,z;
int *p,fun(int &, int &); // 這里顯然是引用操作符啦!
對於
z = x & y; // 很明顯的,這是邏輯與(and)運算
x &= y; // 這里也是
p = &x; // 這是取址運算,注意,新版的C中沒有 =& 雙目運算符
-----------------------------------------------------------------------------------------------------------------------
在C++中,有運算符重載函數,比如
aClass operator&(const aClass &x,const aClass &y);,功能是實施類x和y的邏輯與,並返回aClass的實例,這里operator&中的「&」是被重載的運算符,&x,&y中的「&」是引用操作符。
----------------------------------------------------------------------------------------------------------------------
如果你希望了解編譯程序的細節,請參考相關書籍。

⑤ 用VS編譯和C++源文件的時候,源文件和庫文件是如何鏈接到源文件的具體細節

因為我是學習計算機軟體專業的,故可以給你講一下大概意思,我也不敢保證我講得都是正確的。個人講解僅供參考。這個是需要學習《計算機編譯原理》這門課程的。而且《計算機編譯原理》這門課程在軟體專業中幾乎是最抽象的、難於理解的。
首先關於 Visual Studio編譯器(或者是別的 C/C++編譯器)是如何將用戶親自編寫的源程序經過若干步驟之後,最終變成計算機可執行的二進制代碼程序?這裡面經過了如下步驟:
(1)、詞法分析/語法分析。也就是說當編譯器對用戶編寫的源程序進行編譯時,首先檢查你的詞法(或者是語法)是否正確,這是第一步(這里以 C 語言為例,假如將定義一個整型變數 n 的語句 int n ; 誤寫成了:intt n ; 屬於語法錯誤)。如果這一步都沒有通過編譯器的檢查的話,那麼絕對不會進入第二步。繼續返回編輯狀態進行語法檢查。這種錯誤是最容易檢查的。
(2)、語義分析。這類錯誤就要比(1)困難得多。這類錯誤舉例如下(這類錯誤編譯器只是會給出一個警告信息,但是編譯器是會放過這類錯誤的。故需要編程人員具有較豐富的編程經驗)
void main( )
{
int num ; /* 定義一個整型變數 num */
scanf("%d", &num ) ; /* 從鍵盤上輸入一個整數 */
if( num == 10 ) /* 在這個語句中,如果將邏輯判斷等於號 ==,誤寫為數值等於 =(即:if( num = 10 )),那麼該程序的執行結果始終輸出:Correct。因為該邏輯表達式 if( 10 ) 的真值始終為 1。 */
printf( "Correct !\n" ) ; /* 實際上程序的本意是:如果輸入的數值等於 10,則輸出:Correct ! */
else /* 如果輸入的數值不等於 10 的話,則輸出:Error ! */
printf( "Error !\n" ) ;
}
(3)、在(1)和(2)的基礎上進行中間代碼生成(例如:在Linux 系統下面生成的 *.o 文件、或者是在 WINDOWS 系統下面生成的 *.obj 文件),這類文件還不是最終的可執行文件。
在此過程中,會應用到各種符號表,以便處理用戶程序中使用的各種常量、變數、以及各種函數,等等。
(4)、在前三個階段的基礎上,最終 VS 編譯器再將中間代碼(*.obj 文件)和其本身提供的庫文件(*.LIB)進行鏈接,最終產生可執行程序(Linux 系統使用的編譯器是:gcc,Linux 系統下面的可執行文件名可以任意,WINDOWS 系統下面的可執行文件名為:*.EXE 文件)。
到此為止,一個用戶編寫的源程序,經過上面若干步驟之後,最終產生了可執行程序,此時就可以在機器上的相應的操作系統上執行了。

java常見誤區與細節有哪些

1、在Java中,沒有goto語句。因為大量使用goto語句會降低程序的可讀性和可維護性,所以Java語言取消了goto的使用。同時,為了避免程序員自行使用goto所帶來的混亂,Java語言仍將goto定義為一個關鍵字,但是沒有定義任何語法,故稱為「保留字」。

2 true、false和null在IDE中雖然以不同的顏色顯示,但是並不是關鍵字,而是「字面常量」,就和String類型的abc一樣。

3 定義名稱時盡量避免使用$,因為編譯器在對.java文件進行編譯的時候,會將」$」編譯成頂層類型與底層類型的連接符。見下例:

  • package

  • com.javastack.

  • Test

  • ;

  • public

  • class

  • Outer$Inner

  • {

  • public

  • static

  • void

  • main(

  • String

  • [] args) {

  • Outer

  • o =

  • new

  • Outer

  • ();

  • Outer

  • .

  • Inner

  • i = o.

  • new

  • Inner

  • ();

  • i.innerPrint();

  • }

  • }

  • class

  • Outer

  • {

  • class

  • Inner

  • {

  • void

  • innerPrint() {

  • System

    .

    out

    .println(

    "Inner Print!"

    );

  • }

  • }

  • }

  • 在編譯(javac Test3.java)這段代碼的時候,編譯器會報以下錯誤:Test.java:12: 錯誤: 類重復: com.javastack.Test.Outer.Inner class Inner{ ^

    4Unicode轉義字元處理的非常早,在解析程序之前。例如:

  • // char c1 = 'u00a';

  • // char c2 = 'u00d';

  • 在程序中出現這兩行代碼編譯報錯。這兩個Unicode碼分別表示」換行」和」回車」,所以,在編譯器編譯的時候,代碼是這樣的:

  • // char c1 = '

  • ';

  • // char c2 = '

  • ';

  • 5 Unicode碼使用16位字元編碼,在Java中用char類型來表示。現在Unicode已經擴展到一百萬個字元,超出16位限制的成為增補字元。所有增補字元都不能用字元常量來表示。

    6 當short,byte,char參加運算時,結果為int型,而非與較高的類型相同。如果變數是byte,short,byte類型,當對其賦予編譯時期的常量,而該常量又沒有超過變數的取值范圍時,編譯器就可以進行隱式的收縮轉換。這種隱式的收縮轉換是安全的,因為該收縮轉換只適用於變數的賦值,而不適用於方法調用語句,即不適用於方法調用時的參數傳遞。(詳見java中默認類型轉換的小問題)

    7 注意char類型,這是一個無符號類型。因此,char與short或char與byte之間的轉換必須顯示地使用類型轉換。 從byte到char的轉換為擴展收縮轉換,該轉換比較特殊,即先將byte擴展轉換到int,然後再收縮到char。

    8 在整型數據間的擴展轉換中,如果操作數是char類型(無符號類型),則進行無符號擴展,擴展位為0.如果操作數是byte,short或int(有符號類型),則進行有符號擴展,擴展位為該變數的符號位。

    9 整型數據之間的收縮轉換,僅僅是截斷並丟棄高位,不做任何其他處理。

    100.1+0.2不等於0.3.System.out.println((double)0.1+(double)0.2);這條語句的輸出結果是0.30000000000000004。因為計算機使用二進制來存儲數據,而很多小數都不能夠准確地使用二進制來表示(事實上,大多數地小數都是近似的),就像使用十進制小數不能准確地表示1/3這樣地分數一樣。大多數地浮點型,在計算機中只是近似地存儲其值,而不像整型那樣准確地存儲。又例,這是一個死循環:for(float f = 10.1f;f != 11;f+=0.1f){}

    11 float類型可以保留7~8個有效數字,而double類型可以保留15~16個有效數字,因而當int類型或long類型數值多於double或float地有效數字時,該值的一些最低有效位就會丟失,從而造成精度丟失,這時,就會採用IEEE754最近舍入模式,提取與該整型值最接近的浮點值。盡管整型向浮點型的轉換屬於擴展轉換,但當數值很大或很小(絕對值很大)時,就會產生一定的精度丟失。

    12 i+++j如何計算?(這個問題在C/C++)中討論是沒有多大意義的,因為C/C++依賴於實現的硬體結構,不同的環境結果也會不同。不過在Java中,這個結果是固定的,不受其運行的硬體環境與平台的影響) 答:根據貪心規則,前置++優於後置++,結果是(i++)+j

    13i++和++i其實都是先+1,再賦值。++i,沒什麼好說的;i++,以j=i++;為例在底層的實現是:temp = i;i = i + 1; j = temp; 所以,i=15;i=i++;這個表達式的結果是15.(因為加一之後又執行了一次賦值,從16變回15)

    14 +0與-0在浮點類型變數存儲中,符號位是不同的。當-0和+0參與浮點類型的相關運算(例如相除與求余運算)時,可以產生不同的結果。

    15 浮點的相除與求余運算不同與整型的相除與求余運算,當除數為0時,浮點運算不會產生ArithmeticException異常。

    16 String類是非可變類,其對象一旦創建,就不可銷毀。String類那些看似修改字元序列的方法實際上都是返回新創建的String對象,而不是修改自身對象。

    17 由於String對象是不可改變的,因此具有線程安全性,可以自由地實現共享。

    18 在String類內部,是使用一個字元數組(char[])來維護字元序列的。String的最大長度也就是字元數組的最大長度,理論上最大長度為int類型的最大值,即2147483647.在實際中,一般可獲取的最大值小於理論最大值。

    19 main()方法在表現行為上,與其他方法基本相同,可以重載,由其他方法調用,繼承,隱藏,也可以拋出異常,帶有類型參數。我們也可以在一個程序中通過反射來調用main方法(或其他方法)。

    20 當兩個或多個方法的名稱相同,而參數列表不同時,這幾個方法就構成了重載。重載方法可以根據參數列表對應的類型與參數的個數來區分,但是,參數的名稱、方法的返回類型,方法的異常列表與類型參數不能作為區分重載方法的條件。

    21 究竟選擇哪個方法調用,順序是這樣的:

  • 在第一階段,自動裝箱(拆箱)與可變參數不予考慮,搜索對應形參類型可以匹配實參類型並且形參個數與實參個數相同的方法;

  • 如果在步驟一不存在符合條件的方法,在第二階段,自動裝箱與拆箱將會執行。

  • 如果在步驟二中不存在符合條件的方法,在第三階段,可變參數的方法將會考慮。

  • 如果3個階段都沒有搜索到符合條件的方法,將會產生編譯錯誤。如果如何條件的方法多於一個,將會選擇最明確的方法。最明確的方法定義為:如果A方法的形參列表類型對應的都可以賦值給B方法的形參列表類型,則A方法比B方法明確。如果無法選出最明確的方法,則會產生編譯錯誤。

  • 22 重寫和隱藏的本質區別是:重寫是動態綁定的,根據運行時引用所指向對象的實際類型來決定調用相關類的成員。而隱藏是靜態綁定的,根據編譯時引用的靜態類型來決定調用的相關成員。換句話說,如果子類重寫了父類的方法,當父類的引用指向子類對象時,通過父類的引用調用的是子類方法。如果子類隱藏了父類的方法(成員變數),通過父類的引用調用的仍是父類的方法(成員變數)。

    23 構造器是遞歸調用的,子類的構造器會調用父類的構造器,直到調用Object類的構造器為止。

    24 構造器沒有創建對象,構造器是使用new創建對象時由系統調用的,用來初始化類的實例成員。從順序上說,先是創建對象,然後再調用構造器的。(構造器並沒有產生新的對象)

    25 默認的構造器不為空,該構造器會調用父類的無參構造器,並可能執行實例成員變數的初始化。所以,默認的構造器至少調用了父類的構造器,它做的工作還可能更多,包括實例變數聲明初始化與實例初始化塊,都是在構造器中執行的。

    26 當==或!=運算符的兩個操作數的類型一個是基本數據類型,另一個是包裝類引用類型時,將引用類型拆箱轉換為基本數據類型,然後比較兩個基本數據類型的值是否相等。

    27 在Java中,數組也是類,數組聲明的引用變數指向數組類型的對象。所有的數組都繼承Object類,並且實現了java.lang.Cloneable與java.io.Serializable介面。數組的成員包括變數length(隱式存在)與從Object類繼承的成員。Cloneable與Serializable是兩個標記的介面,這兩個介面中沒有顯式聲明任何成員。

    28 介面是完全抽象的設計,不能實例化。使A用new方式創建的借口類型,實際上是創建了一個匿名類,該匿名類實現了介面類型。

    29 如果兩個介面聲明了相同的變數x,則當某介面同時繼承這兩個介面,或者某類同時實現這兩個介面時,通過簡單名稱訪問會產生編譯錯誤。

    30 如果兩個介面中聲明了相同名稱的方法m,並且兩個方法沒有構成重載,則當某介面能夠同時繼承這兩個介面,或者某類能夠同時繼承這兩個介面時,必須存在一種方法簽名,使得該簽名同時為兩個m方法簽名的子簽名,並且在方法的返回類型上,必須存在一種類型,使得該類型同時為兩個m方法返回類型的可替換類型。

⑦ 編譯器一般由哪種語言開發

其實我在想為什麼匯編語言生成一個簡單的編譯器後,可以用新生成的編譯器再次生成編譯器,例如,C語言開發C的編譯器呢?
這是一個遞歸的思想,舉個例子一看就明白了
用一個大的模具可以生成一個A模具,A模具可以做出來B模具,依次往下推,最終這個小模具可以做出來小盒子用來裝東西。
第一個大模具肯定是手工做出來的第一個模具,但是有了這個大模具後,後面就可以用他自動的生成更多的模具,後面的各種模具加起來又可以造出來更精緻的模具,
所以,自動第一個大模具造出來模具的時候,大模具就可以被拋棄了。
我們都知道編譯程序通常分為下面五個階段:
1)詞法分析
2)語法分析
3)語義分析與中間代碼產生
4)優化
5)目標代碼生成
當然最難的一點就是目標代碼的生成,這一階段實現了最終的翻譯,就是真正把原碼翻譯成可以被CPU直接計算的機器碼(NativeCode)。

⑧ 如何下載一個C語言編譯器具體到細節,不要粘貼的。

你用的不會是Turbo C吧?除了那個,我還沒見到不能直接復制的。而且就算是TurboC也可以現在記事本里寫程序,然後用Turbo C打開的。

⑨ 本科獨立用C語言完成沒有優化的C語言編譯器屬於什麼水平

我覺得水平還是很高的,但意義恐怕不大。編譯器技術是非常成熟的領域,而且由於應用場景的限
制實時,復雜的演算法已經自動出局了,你可選的東西是有限的。編譯器可能有很多實現的形
式,虛擬機/解釋器/靜態編譯器 等,也有成熟的開源實現。作為本科生,而非專門研究該分支的學生,應該合理分配自己學習的時間,如果做這個編譯器就干
掉了大半年,那計網和OS這些課程該咋辦? 

我知道很多人會認為沒有做編譯器優化特指中段優化,不考慮機器碼上的優化比較劃水。但編
譯器優化是一個很復雜的東西:首先它和你用的IR表示有關而且是強烈耦合,SSA IR基本還
好,有開源代碼和文獻記載,你想要的都能在網上挖到但這怎麼體現你的水平是吧。你
要考慮編譯器的性能,盡管編譯器的後端優化基本上可以納入到某種PEabstract interpretation的
范疇中。

要不然你可以通過編寫插件的方式白嫖例如visual studio code這類軟
件的強大編輯功能,如果你寫的不是c compiler,你也可以盡量把語法設計得很像c,這樣你又能進一步
白嫖其強大的intellisense code,當然仍然有不少人或者應該說團隊達到了這一步,到這里,應該卷死
了99.99%的同行應該毫無問題。

熱點內容
內置存儲卡可以拆嗎 發布:2025-05-18 04:16:35 瀏覽:333
編譯原理課時設置 發布:2025-05-18 04:13:28 瀏覽:374
linux中進入ip地址伺服器 發布:2025-05-18 04:11:21 瀏覽:609
java用什麼軟體寫 發布:2025-05-18 03:56:19 瀏覽:29
linux配置vim編譯c 發布:2025-05-18 03:55:07 瀏覽:103
砸百鬼腳本 發布:2025-05-18 03:53:34 瀏覽:939
安卓手機如何拍視頻和蘋果一樣 發布:2025-05-18 03:40:47 瀏覽:736
為什麼安卓手機連不上蘋果7熱點 發布:2025-05-18 03:40:13 瀏覽:800
網卡訪問 發布:2025-05-18 03:35:04 瀏覽:507
接收和發送伺服器地址 發布:2025-05-18 03:33:48 瀏覽:369