<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] # 一切都是地址 我們知道,數據是保存在內存中的,對于計算機硬件來說,必須知道它的地址才能使用。變量名、函數名等僅僅是地址的一種助記符,目的是在編程時更加方便地使用數據,當源文件被編譯成可執行文件后,這些標識符都不存在了,它們被替換成了數據的地址。 假設變量 a、b、c 的地址分別為 `0X1000`、`0X1004`、`0X1008`,加法運算的機器指令為 1010,賦值運算的機器指令為 1110,那么在C語言中實現加法運算的代碼為: ~~~ c = a + b; ~~~ 生成可執行文件后的機器碼為: ~~~ 1010 ?0X1000 ?0X1004 ?//將兩個數據相加的值保存在一個臨時區域 1110 ?0X1008 ?//將臨時區域中的數據復制到地址為0X1008的內存中 ~~~ **編譯器和鏈接器的一項重要任務就是將助記符替換成地址。** # 匯編語言的誕生 任何程序的執行,最終都要依靠計算機硬件來完成。現代計算機硬件都是大規模集成電路,它只認識高低兩個電平(電壓),高電平一般為 5V,用`1`表示,低電平一般為 0V,用`0`表示。也就是說,在計算機底層,沒有文字、數字、圖像、視頻等豐富多彩的可視化元素,只有 0 和 1 兩個二進制數字,這就是機器語言。 計算機剛剛誕生的時候沒有編程語言,人們直接使用機器語言(二進制)編程。現在假設有一種跳轉指令,它的二進制形式為 0001,如果需要執行地址為 1010 的代碼,那么可以這樣寫: ~~~ 0001 ?1010 ~~~ > 所謂跳轉,就是在執行當前代碼塊時轉而執行其他的代碼塊。從本質上講,C語言中的函數就是一個代碼塊,當發生函數調用時,就會執行其他的代碼塊,這個過程就是通過跳轉指令來完成的。 那么現在問題來了,程序并不是一寫好就永遠不變化的,它可能會經常被修改。比如我們在地址 1010 之前插入了其他指令,那么原來的代碼就得往后移動,上面的跳轉指令的跳轉地址也得相應地調整。 在這個過程中,程序員需要人工重新計算每個子程序或者跳轉的目標地址,這種重新計算各個目標地址的過程叫做重定位(Relocation)。每次程序修改時,這些位置都要重新計算,十分繁瑣又耗時,并且很容易出錯。 如果程序包含了多個源文件,就很可能會有跨文件的跳轉,這種人工重定位的方式在程序擁有多個模塊時會導致更加嚴重的問題。 沒辦法,這種黑暗的程序員生活是沒辦法容忍的,于是先驅們發明了匯編語言(Assembly),這相比機器語言來說是個很大的進步。 匯編語言使用接近人類的各種符號和標記來幫助記憶,比如用`jmp`表示跳轉指令,用`func`表示一個子程序(C語言中的函數就是一個子程序)的起始地址,這種符號的方法使得人們從具體的機器指令和二進制地址中解放出來。 將上面的機器指令使用匯編代碼來書寫: ~~~ jmp func ~~~ 這樣,不管在 func 之前增加或者減少了多少條指令導致 func 的地址發生了變化,匯編器在每次匯編程序的時候會重新計算 func 這個符號的地址,然后把所有使用到 func 的地方修正為新的地址,整個過程不需要人工參與。對于一個有成千上百個類似的符號的程序,人們終于擺脫了這種低級的繁瑣的計算地址的工作,用一句政治口號來說就是“極大地解放了生產力”。 符號(Symbol)這個概念隨著匯編語言的普及被廣泛接受,它用來表示一個地址,這個地址可能是一段子程序(后來發展為函數)的起始地址,也可以是一個變量的地址。 # C語言的誕生 匯編語言的主要作用是為機器指令提供了助記符,大部分匯編代碼和機器指令是一一對應的,這在匯編被發明的初期確實令程序員非常欣喜。 后來隨著軟件規模的日漸龐大,代碼量開始瘋長,匯編語言的缺點逐漸暴露出來。匯編雖然提供了多種符號,但它依然非常接近計算機硬件,程序員要考慮很多細節問題和邊界問題,并且不利于模塊化開發,所以后來人們發明了C語言。 C語言是比匯編更加高級的編程語言,極大地提高了開發效率,以加法為例,C語言只需要一條語句,匯編卻需要四五條。 # 模塊化開發 現代軟件的規模往往都很大,動輒數百萬行代碼,程序員需要把它們分散到成百上千個模塊中。這些模塊之間相互依賴又相互獨立,原則上每個模塊都可以單獨開發、編譯、測試,改變一個模塊中的代碼不需要編譯整個程序。 > 在C語言中,一個模塊可以認為是一個源文件(.c 文件)。 在程序被分隔成多個模塊后,需要解決的一個重要問題是如何將這些模塊組合成一個單一的可執行程序。在C語言中,模塊之間的依賴關系主要有兩種:一種是模塊間的函數調用,另外一種是模塊間的變量訪問。 函數調用需要知道函數的首地址,變量訪問需要知道變量的地址,所以這兩種方式可以歸結為一種,那就是模塊間的符號引用。 模塊間依靠符號來“通信”類似于拼圖版,定義符號的模塊多出一個區域,引用符號的模塊剛好少了那一塊區域,兩者剛好完美組合。如下圖所示: ![](https://box.kancloud.cn/44c08aaf858bb15aeff1e2cd307425c2_167x164.png) 這種通過符號將多個模塊拼接為一個獨立的程序的過程就叫做鏈接(Linking)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看