編譯期確定端序
『壹』 虛函數調用為什麼不能在編譯時確定
在編譯的時候編譯器並不知道用戶選擇的是哪種類型的對象。,如果不是虛函數,則採用早綁定,函數體與函數調用在程序運行之前就綁定了.當函數聲明為虛函數時,,編譯器通過創建一個虛函數表存放虛函數的地址,在運行時,通過基類指針做虛函數調用時,編譯器靜態的插入能取得這個虛函數指針並在虛函數表中找到正確的函數版本.
『貳』 什麼叫編碼期,編譯期,運行期在各個期間都做了什麼
編碼期就是編寫代碼,代碼這時為文本狀態,編譯期即將文本代碼轉換為中間碼的過程,運行期就是執行程序。
『叄』 請問java中的編譯期和運行期有什麼區別
編譯時是調用檢查你的源程序是否有語法錯誤,如果沒有就將其翻譯成位元組碼文件。即.class文件。
運行時是java虛擬機解釋執行位元組碼文件。
『肆』 匯編指令在編譯時就已經確定了在內存中的地址
程序源代碼編譯連接生成可執行文件後,就確定了所有指令的偏指,只是在執行時才確定其段指。所以你在Linux下用objmp就可以看到overhere標簽的地址,其實這是偏指。
『伍』 如果一個工程中有多個C++源文件,怎麼確定先編譯哪個源文件呢
授人以魚,不如授人以漁.建議樓主好好看看<<C++ primer>>這本書,目前有中文第四版,我非常喜歡它,我也是去年十月份開始學習C++的,看完它再看<<effective C++>>和<<more effective C++>> , 尤其是<<effective C++>>,簡直是C++的聖經,非看不可...最後到高級了.你還可以看看<<深入探索C++對象模型>>...我全看完了,感覺受益匪淺.
好了,下面開始解答問題:
解答問題之前,復習一下基本概念;
1:C++中的全局變數,在整個程序中只能定義一次,但可以聲明多次(不限次數); 在一個地方定義,,然後在其他地方使用時,要先聲明一下;
2:什麼叫變數定義? 比如 int i; 這就是定義;
而 extern int i; 則 只是聲明;
但如果寫作 extern int i = 0; 則這也是定義,不是聲明;(是不是有點繞??熟悉了就很簡單了)
所以,我覺得你的問題.實際上是源自你對C++語法中變數的定義和聲明這兩個概念的模糊;
你說你在a.cpp 中聲明 i, 而在b.cpp中必須用extern 聲明才可通過編譯,這是正常的..因為你的i是在a.cpp中定義的..
你說你在b.cpp中聲明i, a.cpp中是否使用extern都可以通過編譯,這個問題嘛.我估計你的代碼實際上仍然是在a.cpp中定義了i,而b.cpp中定義的i不是全局的.
至於你說如果有多個源文件.那麼編譯順序如何確定.這個問題很難回答你,恐怕不同的編譯器對此的處理都不大相同..我覺得你不應該考慮這個問題..實際上編譯器會把不同的源文件分別、單獨地編譯成獨立的模塊,最後再鏈接成一個可執行程序,因為它們都是獨立編譯的模塊,理論上說.編譯順序是不重要的.
我覺得倒是應該告訴你如何正確地管理和使用全局變數;
首先,建立一個 "global.h"(文件名隨你,我這里舉個例子而已,記得在頭文件里加上頭文件保護符哦!如果你告訴我你不知道什麼是頭文件保護符,我強烈建議你不要再往下看了..立刻去買一本C++primer吧);
在global.h文件中.聲明你所需要的所有全局變數,以下是 global.h的內容:
#ifndef GLOBAL_H
#define GLOBAL_H
extern int g_i; // 此處是聲明,另外,在全局變數前加一個 g_ 是好習慣.
#endif
然後新建一個 global.cpp文件,包含 global.h文件,接著,定義所有的全局變數,
以下是global.cpp的內容:
#include "global.h"
int g_i = 1982; // 此處是定義!!!
至此,一切搞定,最後,在你需要用到全局變數的cpp文件中包含 global.h吧...比如你的a.cpp和b.cpp; 編譯順利了吧?
/////////////////////////////////////////////
看到樓主的新問題了..我再補充回答一下.
問題1:我的疑問是,如果在my.cpp中定義了theApp,則必須在mfc.cpp中用extern聲明theApp,否則編譯出錯;但是如果在mfc.cpp中定義theApp,則不必在my.cpp中聲明,編譯也能夠通過,這是為什麼呢?
我的回答: 這個問題還是聲明和定義的問題.我之前說過了.一個變數(比如你的這個theApp),在整個程序中只能定義一次, 然後在需要使用它的地方,要先聲明後使用.
因此,看看實際情況:你在my.cpp中定義了theApp,當你在mfc.cpp中要使用它,當然要先聲明它咯,而聲明變數必須加上extern,不然就變成定義了,那麼就會導致你在my.cpp和mfc.cpp中定義同名全局變數兩次,自然就無法通過編譯.
而如果你在mfc.cpp中定義theApp的話,因為在my.cpp中沒有直接用到 theApp.所以,就不需要聲明了.這下清楚了吧?呵呵.
還有,補充一個基礎知識,,我們通常寫 int i; 這樣的語句是"定義","定義"實際上就起到了"聲明"的作用; 所以,如果你不是定義變數,而是單純要聲明一個外部的全局變數(也就是其他cpp文件里的全局變數)的時候,是肯定要加extern的.
我覺得樓主是對 與要加extern感到詫異.
問題2:
這個程序我運行的結果是只有構造函數的那些輸出語句執行了,而析構函數的那些輸出語句並沒有執行,這又是為什麼呢?
這個講起來有點多.涉及到一個C++程序的啟動過程:我簡單地說說,
以windows為例,點擊一個exe程序後,系統創建一個"進程內核對象",創建4G虛擬內存空間以及其他的一些執行程序需要的資源,然後創建"線程內核對象",啟動一個線程(也就是主線程了),這個線程調用一個 C++ startup函數,該函數會初始化 你的程序中的所有全局變數,( 這個時候你就看到你 theApp的那些基類的構造函數的執行,並列印出來),所有全局變數構造好以後,才開始執行你寫的main函數.
然後,你的main函數 return了.這時,執行一個C++執行期函數exit(),析構你的所有全局變數(也就是theApp), 但這個時候你的console窗口已經退出了.所以你看不到那些析構函數執行時的列印信息了.呵呵.
另外:我真的非常推薦樓主先好好看看<<C++ primer>>和<<effective C++>>這兩本書,不要把<<深入淺出mfc>>當成C++教材來看,雖然這本書很好,並且通過mfc,很好地示範了C++ 繼承,虛函數的妙用.但是,<深入淺出mfc>的作者侯捷說的好:勿於浮沙築高台.. 基礎打牢非常關鍵. 當你把C++的基礎知識搞清以後,再看深入淺出 mfc 其實是很簡單的..
『陸』 簡述將源程序編譯成可執行程序的過程
一個源程序到一個可執行程序的過程:預編譯、編譯、匯編、鏈接。其中,編譯是主要部分,其中又分為六個部分:詞法分析、語法分析、語義分析、中間代碼生成、目標代碼生成和優化。
預編譯:主要處理源代碼文件中的以「#」開頭的預編譯指令。處理規則如下:
1、刪除所有的#define,展開所有的宏定義。
2、處理所有的條件預編譯指令,如「#if」、「#endif」、「#ifdef」、「#elif」和「#else」。
3、處理「#include」預編譯指令,將文件內容替換到它的位置,這個過程是遞歸進行的,文件中包含其他文件。
4、刪除所有的注釋,「//」和「/**/」。
5、保留所有的#pragma 編譯器指令,編譯器需要用到他們,如:#pragma once 是為了防止有文件被重復引用。
6、添加行號和文件標識,便於編譯時編譯器產生調試用的行號信息,和編譯時產生編譯錯誤或警告是能夠顯示行號。
(6)編譯期確定端序擴展閱讀:
編譯過程中語法分析器只是完成了對表達式語法層面的分析,語義分析器則對表達式是否有意義進行判斷,其分析的語義是靜態語義——在編譯期能分期的語義,相對應的動態語義是在運行期才能確定的語義。
其中,靜態語義通常包括:聲明和類型的匹配,類型的轉換,那麼語義分析就會對這些方面進行檢查,例如將一個int型賦值給int*型時,語義分析程序會發現這個類型不匹配,編譯器就會報錯。
『柒』 判斷當前程序運行的計算機平台的位元組序是大端序還是小端序
Java編譯後.class文件是二進制位元組碼,而不是系統能識別的機器碼,所以直接運行.class文件,系統不能識別,而Java為了解決這個問題,採用一個中間轉換過程,必須要把.class文件,轉換成對應操作系統所能識別的機器碼。 於是把這個轉換的任務交給了JVM(java虛擬機),所以只要安裝虛擬機的操作系統就能運行Java開發的程序,而不管你用的什麼操作系統,因為轉換工作是由虛擬機來幫你完成的。 舉個例子:假如:你(相當於Java程序)和美國人(一種操作系統)談話,而你不懂英語,美國人不懂漢語,怎麼辦呢?你會想到找個翻譯(Java虛擬機),把你說的話翻譯成英語。 這個時候你又和一個德國人說,只要通用的翻譯就可以了
『捌』 編譯程序的工作過程一般可以劃分為哪5個基本階段,還自始至終伴隨進行哪兩項工作
1、編譯程序把一個源程序翻譯成目標程序的工作過程分為五個階段:詞法分析;語法分析;中間代碼生成;代碼優化;目標代碼生成。
2、編譯程序的工作過程一般自始至終伴隨進行信息表管理和出錯處理兩項工作。
主要是進行詞法分析和語法分析,又稱為源程序分析,分析過程中發現有語法錯誤,給出提示信息。
(8)編譯期確定端序擴展閱讀:
解釋程序是一種語言處理程序,在詞法、語法和語義分析方面與編譯程序的工作原理基本相同,但在運行用戶程序時,它直接執行源程序或源程序的內部形式(中間代碼)。因此,解釋程序並不產生目標程序,這是它和編譯程序的主要區別。解釋程序的工作過程如下:
1、由總控程序完成初始化工作。
2、依次從源程序中取出一條語句進行語法檢查,如有錯,輸出錯誤信息;如果通過了語法檢查,則根據語句翻澤成相應的指令並執行它。
3、檢查源程序是否已經全部解釋執行完畢,如果未完成則繼續解釋並執行下一條語句,直到全部語句都處理完畢。
『玖』 程序的編譯期,鏈接期, 運行期各執行哪些操作
參考一下:
源文件的編譯過程包含兩個主要階段,而它們之間的轉換是自動的。第一個階段是預處理階段,在正式的編譯階段之前進行。預處理階段將根據已放置在文件中的預處理指令來修改源文件的內容。#include指令就是一個預處理指令,它把頭文件的內容添加到.cpp文件中還有其他許多預處理指令
這個在編譯之前修改源文件的方式提供了很大的靈活性,以適應不同的計算機和操作系統環境的限制。一個環境需要的代碼跟另一個環境所需的代碼可能有所不同,因為可用的硬體或操作系統是不同的。在許多情況下,可以把用於不同環境的代碼放在同一個文件中,再在預處理階段修改代碼,使之適應當前的環境。
預處理器顯示為一個獨立的操作,但一般不能獨立於編譯器來執行這個操作。調用編譯器會自動執行預處理過程,之後才編譯代碼。
編譯器為給定源文件輸出的是機器碼,執行這個過程需要較長時間。在對象文件之間並沒有建立任何連接。對應於某個源文件的對象文件包含在其他源文件中定義的函數引用或其他指定項的引用,而這些函數或項仍沒有被解析。同樣,也沒有建立同庫函數的鏈接。實際上,這些函數的代碼並不是文件的一部分。這些工作是由鏈接程序(有時稱為鏈接編輯器)完成的
鏈接程序把所有對象文件中的機器碼組合在一起,並解析它們之間的交叉引用。它還集成了對象模塊所使用的庫函數的代碼。這是鏈接程序的一種簡化表示,因為這里假定在可執行模塊中,模塊之間的所有鏈接都是靜態建立的。實際上有些鏈接是動態的,即這些鏈接是在程序執行時建立的。
鏈接程序靜態地建立函數之間的鏈接,即在程序執行之前建立組成程序的源文件中所包含的函數鏈接。動態建立的函數之間的鏈接(在程序執行過程中建立的鏈接)將函數編譯並鏈接起來,創建另一種可執行模塊—— 動態鏈接庫或共享庫。動態鏈接庫中的函數鏈接是在程序調用函數時才建立的,在程序調用之前,該鏈接是不存在的。
動態鏈接庫有幾個重要的優點。一個主要的優點是動態鏈接庫中的函數可以在幾個並行執行的程序之間共享,這將節省相同函數佔用的內存空間。另一個優點是動態鏈接庫在調用其中的函數之前是不會載入到內存中的。也就是說,如果不使用給定動態鏈接庫中的函數,該動態鏈接庫就不會佔用內存空間
『拾』 Java代碼的編譯期綁定和運行期綁定是什麼意思
如果打包成jar的話很好如果是exe的話就有點麻煩了可參考:想要把java生成可執行文件需要第三方軟體的支持,不過在沒有安裝JDK的機器上是不可能運行JAVA程序的,哪怕是編譯成為exe文件。將Java應用程序本地編譯為EXE的幾種方法(推薦使用JOVE和JET)1.從獲得一個TowerJ編譯器,該編譯器可以將你的CLASS文件編譯成EXE文件。2.利用微軟的SDK-Java4.0所提供的jexegen.exe創建EXE文件,這個軟體可以從微軟的網站免費下載,地址如下:7.Instantiations公司的JOVE/jove/ejovesystem.htmJOVE公司合並了以前的SuperCede,一個優秀的本地編譯器,現在SuperCede已經不復存在了。8.JToEXEBravoZuluConsulting,Inc開發的一款本地編譯器,本來可以從該公司的網頁上免費下載的,不過目前在該公司的主頁上找不到了。