函數,從編輯到編譯 (上)

来源:https://www.cnblogs.com/tobe98/archive/2019/09/21/11564536.html
-Advertisement-
Play Games

0. 序 我從一生下來就呆在這個昏暗的地方。 我不明白為什麼程式員這麼喜歡 Dark Mode,Brighten Mode 才是我的最愛。聽說最近連 iphone 都開始支持 Dark Mode 了,沒話講。。。說好的絕不妥協呢? 我周圍是熙熙攘攘的函數群,穿插著變數聲明和巨集定義。 在我們這裡,函數 ...


0. 序

我從一生下來就呆在這個昏暗的地方。

我不明白為什麼程式員這麼喜歡 Dark Mode,Brighten Mode 才是我的最愛。聽說最近連 iphone 都開始支持 Dark Mode 了,沒話講。。。說好的絕不妥協呢?

我周圍是熙熙攘攘的函數群,穿插著變數聲明和巨集定義。

在我們這裡,函數是一等公民。

當然,不光在 C++,在面向過程的 C 語言、面向對象的 Java ,尤其是在那些函數式編程的語言里,我們都扮演著舉足輕重的角色。

能力越大,責任越大。我和一群函數伙伴們就負責維護著程式的功能。每個函數的一小步,合起來就是功能模塊的一大步。

作為一門靜態編譯型語言,我們不像那些解釋語言一樣,寫完就能直接運行,而是要先經過編譯這一道坎,成為機器語言,才能夠運行在我們賴以生存的機器上。

這道坎不是那麼好過的,再頂尖的程式員,也會在這上面栽跟頭。

放在往常,雖然程式偶爾會出 bug ,但大家齊心協力,可謂蟲(bug)擋殺蟲,過五關斬六將,整個程式也稱得上是井井有條。

但這次,我們遇到了大問題。

1. 預編譯

今天的一切看起來都很平凡,至少我是這麼認為的。

屏幕外的程式員像平常一樣敲著代碼,我們像平常迎接著新函數的到來,像平常一樣嬉笑怒罵,像平常一樣期待著預編譯進程的到來。

預編譯進程是整個編譯進程的先鋒。

像往常一樣,我們從磁碟出發,沿著匯流排來到了記憶體。這裡就是進程的工作車間。

預編譯進程第一步會 刪除所有 #define,展開巨集定義。處理條件預編譯指令。

#define WINDOWS
#define BUFSIZE 1024
#define DEPTH 4
#define DECODE "utf-8"
...

上面的就是巨集定義,每次我們都要在預編譯進程的指揮下,把語句里出現的巨集替換成對應的值。

這一步其實本來不需要我們乾的,程式員怕麻煩,想要做到“一處修改,處處更改”,就發明瞭巨集定義,讓編譯器來乾這些“臟活累活”。

處理條件預編譯指令就有點不一樣了:

//windows or linux
#ifdef WINDOWS
<experssion1>
#else
<experssion2>
#endif

如果巨集定義有這個 WINDOWS,就只留下 <experssion1>,沒有的話就留 <experssion2> 。說白了,就是個預編譯階段能執行的 if... else ... 語句。上面的語句一處理,就變成了:

<experssion1>

對,註釋也會被刪除。

可憐那些註釋,這一輩子都不曾領略 CPU 里的風景。

第二步是處理 #include預編譯指令。

這一步就比上面的複雜多了。用專業的話來說,處理 “#include ”預編譯指令,就是將被包含的文件插入到該預編譯指令的位置。這個過程是遞歸進行的,也就是說被包含的文件可能還包含其他文件。

#include "config.h"
<expressions>

別看他們現在就只有短短兩句,等把 config.h文件內容複製過來,信息量一下子就大了。

#ifndef _CONFIG_H_
#define _CONFIG_H_

#define VERSION "1.0.0"
#define MODE 1
...
...
#endif

<expressions>

補充一句,這個 .h 尾碼的家伙,叫頭文件。他是我們與其他文件的函數公民的溝通渠道。

頭文件這個家伙和源文件不太一樣,他是包含功能函數、數據介面聲明的載體文件,主要用於保存程式的聲明。也就是說,頭文件里是沒有函數的——我們曾多次試圖占領頭文件的領地,但都沒有成功——都是因為程式員的約束。

每個頭文件都會帶有一組條件預編譯語句,用來防止自己被多次編譯。

至於怎麼做到的,這太簡單了,我不說你也能想出來。

聽說有的編譯器還支持 #pragma once ,添在頭文件第一行就能做到相同的事情。可惜我們的編譯器有點舊,不相容他們。

最後這步就比較快了,添加行號和文件名標識

走到這裡,我們已經得到了編譯器調試的需要的行號信息,如果編譯到哪一步出錯,或者出現 warning 這樣的警告,就能把行號顯示出來,方便程式員及時發現問題源頭。

今天的預編譯比我想象中要快一點,可能這次沒什麼進程跟我們搶 CPU 資源吧。

預編譯階段結束,# 的數量大大減少,僅剩下幾個 #pragma 指令留在這裡。

和其他巨集定義指令不一樣的是,#pragma 是能夠跟編譯器平起平坐的存在,預編譯進程見了都得避讓三分。

#pragma  warning( disable: 4507 34; once: 4385; error: 164 )

像這條指令,就是專門給編譯器看的,意思是 ‘不顯示4507和34號警告信息 ,4385號警告信息僅報告一次,把164號警告信息作為一個錯誤’ 。可以說,她是程式員和編譯器之間的信鴿。

對於我來說,預編譯階段是比較輕鬆的,最複雜也只是處理條件預編譯指令——刪除幾行代碼罷了。

未完待續

如果大家對文章有什麼看法和意見,歡迎提出來~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目的:寫給自己看的,不如其他大神全,以後慢慢修修改改 一:如何判斷數據是否垃圾數據 1.引用計數法 當創建一個對象時,為此對象分配一個引用計數器。當有其他對象引用這個對象時,計數器就+1。當引用失效了,計數器-1。 當一個對象的引用計數器=0時,此對象就可以被回收。 優點:原理簡單,實現方便。 缺點 ...
  • AJAX框架Day1 1、Ajax引言 a) 概念 Asynchronous Javascript And XML (非同步請求 javaScript And XML) b) 傳統的請求 2、非同步請求的開發 a) 非同步請求對象的創建 javascript: XmlHttpRequest對象 xhr C ...
  • 本周的 上分享了一篇小文章,它裡面提到的冷知識很有意思,我稍作補充,分享給大家。 它提到的部分問題,讀者們可以先思考下: 若兩個元組相等,即 a==b 且 a is b,那麼相同索引的元素(如 a[0] 、b[0])是否必然相等呢? 若兩個對象的 hash 結果相等,即 hash(a) == has ...
  • JDK(Java Development Kit) JDK顧名思義就是Java開發工具包,是Sun Microsystems針對Java開發員的產品,是Java程式員通過Java語言編寫程式所需的開發工具包,JDK包含了JRE,同時還包含了編譯Java源碼的編輯器Javac,還包含了很多Java程式 ...
  • 什麼是 PHP 擴展 通俗說,PHP 擴展是增強 PHP 語言功能的插件。PHP 提供了編程語言的語法,比如分支、迴圈、函數、類等,這些是 PHP 本身所提供的。在某些情況下需要在 PHP 語言的基礎上進行擴展,那麼就需要通過 PHP 底層提供的數據結構和介面來開發 PHP 擴展,從而來補充或擴展 ...
  • 聲明 :本博客僅僅是一個初學者的學習記錄、心得總結,其中肯定有許多錯誤,不具有參考價值,歡迎大佬指正,謝謝!想和我交流、一起學習、一起進步的朋友可以加我微信Liu__66666666 這是簡單學習一遍之後的記錄,後期還會修改。 一、學習內容 1. "jvm簡介" 2. 記憶體模型 3. 垃圾回收機制 ...
  • 恢復內容開始 目錄 1. 分支結構 1.1 初步介紹 1.2 使用案例 1.3 練習 2.迴圈結構 1.1 初步介紹 1.2 使用案例 目錄 1. 分支結構 1.1 初步介紹 1.2 使用案例 1.3 練習 2.迴圈結構 1.1 初步介紹 1.2 使用案例 1. 分支結構 1.1 初步介紹 1.2 ...
  • ZooKeeper技術的極少以及ZooKeeper集群的搭建 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...