<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C++編譯流程

      編譯器(Compiler)

      編譯器是一種把人類寫的源代碼(C/C++)翻譯成計算機能執行的機器碼的程序。

      在 C++ 中,常用的編譯器有:

      編譯器平臺說明
      GCC(g++) Linux / WSL / Windows(MinGW) GNU 開源編譯器,使用最廣泛
      Clang macOS / Linux 快速現代的 LLVM 編譯器
      MSVC(cl.exe) Windows 微軟官方 C++ 編譯器,集成在 Visual Studio 中
      MinGW / MinGW-w64 Windows GCC 的 Windows 移植版

      編譯流程

      C++ 程序從 .cpp 文件到 .exe 可執行文件,會經歷 四個主要階段
      源代碼 → 預處理 → 編譯 → 匯編 → 鏈接 → 可執行程序

      1 預處理(Preprocessing)

      • 處理 #include#define、條件編譯等

      • 生成 .i 文件(展開后的源代碼)

      示例

      #include <iostream>
      
      #define DEBUG_MODE
      
      #ifndef PI
      #define PI 3.14
      #endif
      
      int main() {
      #ifdef DEBUG_MODE
          std::cout << "Debug mode is ON" << std::endl;
      #endif
      
          std::cout << "PI is " << PI << std::endl;
          return 0;
      }
      

      編譯器會在這一步執行:

      • 處理 #include <iostream>:將 <iostream> 的內容插入代碼中(即標準輸入輸出的定義);

      • 定義宏 DEBUG_MODE

      • 檢查是否已經定義了宏 PI

        • 因為還沒定義,#define PI 3.14 會生效;

      • 檢查 #ifdef DEBUG_MODE 是否成立:

        • 成立 → 保留 std::cout << "Debug mode is ON" << std::endl;

      • 宏替換:將 PI 替換為 3.14

      2 編譯(Compilation)

      • 把預處理后的 .i 文件轉成匯編語言(.s 文件)

      • 檢查語法、類型、做優化

      3 匯編(Assembly)

      • 把匯編代碼 .s 翻譯成目標代碼 .o(或 .obj

      4 鏈接(Linking)

      • 把多個 .o 文件和系統庫連接起來

      • 解決函數調用、變量引用等鏈接

      • 最終生成 .exe 可執行文件

      編譯四個階段命令(使用 g++

      g++ -E main.cpp -o main.i      // -E:只執行預處理
      g++ -S main.i -o main.s        // -S:把代碼編譯成匯編語言
      g++ -c main.s -o main.o        //-c:把匯編代碼翻譯成目標文件(機器指令)
      g++ main.o -o hello            // 把目標文件 main.o 和標準庫鏈接成最終的可執行程序 main.exe

       或者一步到位

      g++ -o hello main.cpp

      示例 多文件項目示例

      ?? 項目結構

      my_project/
      ├── main.cpp        // 主函數
      ├── math.h          // 頭文件(聲明函數)
      ├── math.cpp        // 實現文件(定義函數)d

      ??代碼

      // math.h
      #ifndef MATH_H
      #define MATH_H
      
      int add(int a, int b);
      int subtract(int a, int b);
      
      #endif
      
      // math.cpp
      #include "math.h"
      
      int add(int a, int b) {
          return a + b;
      }
      
      int subtract(int a, int b) {
          return a - b;
      }
      
      // main.cpp
      #include <iostream>
      #include "math.h"
      
      int main() {
          int x = 10, y = 5;
          std::cout << "x + y = " << add(x, y) << std::endl;
          std::cout << "x - y = " << subtract(x, y) << std::endl;
          return 0;
      }
      

      打開 WSL 終端,依次輸入

      # 創建項目目錄
      mkdir my_project
      cd my_project
      
      # 創建源文件(使用 nano 編輯器 【Ctrl + O】保存文件 【Enter】確認保存文件名  【Ctrl + X】退出編輯器)
      nano main.cpp        # 創建主函數文件 
      nano math.h          # 創建頭文件,聲明函數
      nano math.cpp        # 創建實現文件,定義函數
      
      # 編譯多個 .cpp 文件為一個可執行程序
      g++  -o app main.cpp math.cpp
      
      # 運行程序
      ./app
      

      Makefile

      項目通常有多個源文件,手動寫命令很繁瑣,特別文件多時容易出錯。Makefile可以自動、智能地管理編譯流程,省時省力,減少錯誤。以上面的例子為例,假定最終生成的可執行文件是app,中間步驟還需要生成main.o和math.o兩個文件。根據上述依賴關系,可以寫出Makefile如下:

      # 目標:生成可執行文件 app
      app: main.o math.o
          # 使用 g++ 鏈接 main.o 和 math.o,生成可執行文件 app
          g++ -o app main.o math.o
      
      # 目標:編譯 main.cpp 為目標文件 main.o
      main.o: main.cpp
          # 使用 g++ 編譯 main.cpp,生成目標文件 main.o
          g++ -c main.cpp
      
      # 目標:編譯 math.cpp 為目標文件 math.o,加上math.h如果頭文件變化就會重新編譯math.o
      math.o: math.cpp math.h
          # 使用 g++ 編譯 math.cpp,生成目標文件 math.o
          g++ -c math.cpp
      
      # 目標:清理編譯生成的文件
      clean:
          # 刪除所有的目標文件和可執行文件
          rm -f *.o app
      

      執行make,輸出如下:

      g++ -c main.cpp
      g++ -c math.cpp
      g++ -o app main.o math.o
      

      使用隱式規則

      我們把.o的規則刪掉,也能正常編譯

      # 只保留生成app的規則:
      app: main.o math.o
          g++ -o app main.o math.o
      clean:
          rm -f *.o app
      

      執行make,輸出如下:

      g++    -c -o main.o main.cpp
      g++    -c -o math.o math.cpp
      g++ -o app main.o math.o
      

      在使用 make 時,如果沒有顯式地為 .o 文件(如 main.omath.o)定義規則,make 會自動應用內置的隱式規則來生成這些目標文件。這種機制使得 Makefile 更加簡潔,避免了重復編寫常見的編譯命令。

      但是由于 make 的隱式規則默認只根據目標文件和源文件的修改時間來判斷是否需要重新編譯,它并不會自動跟蹤頭文件(.h 文件)的變化。因此,即使修改了頭文件,make 也可能不會重新編譯依賴于該頭文件的源文件(.cpp 文件)。

      使用變量

      當項目中有多個源文件時,使用變量可以使 Makefile 更簡潔、易于維護。變量定義用變量名 = 值或者變量名 := 值,通常變量名全大寫。引用變量用$(變量名),非常簡單。比如上面的例子,可以寫成:

      OBJS = main.o math.o
      TARGET = app
      
      $(TARGET): $(OBJS)
      	g++ -o $(TARGET) $(OBJS)
      
      clean:
      	rm -f *.o $(TARGET)

      我們還可以用變量$(CXX)替換命令g++,在 Makefile 中,$(CXX) 是一個預定義的變量,表示 C++ 編譯器的命令。默認情況下,$(CXX) 的值是 g++使用這個變量的好處是:

      • 可配置性您可以在命令行中通過 make CXX=clang++ 來指定使用 clang++ 作為編譯器,而無需修改 Makefile。

      • 可移植性使用 $(CXX) 可以使您的 Makefile 更具可移植性,因為它允許用戶根據需要選擇不同的編譯器。

      OBJS = main.o math.o
      TARGET = app
      
      $(TARGET): $(OBJS)
      	$(CXX) -o $(TARGET) $(OBJS)
      
      clean:
      	rm -f *.o $(TARGET)
      

      引入自動變量(如 $@$^)進一步提高規則的通用性和可維護性。$@表示目標文件,$^表示所有依賴文件

      OBJS = main.o math.o
      TARGET = app
      
      $(TARGET): $(OBJS)
      	$(CXX) -o $@ $^
      
      clean:
      	rm -f *.o $(TARGET)
      

      使用模式規則

       使用隱式規則可以讓make在必要時自動創建.o文件的規則,但make的隱式規則的命令是固定的,對于xyz.o: xyz.cpp,它實際上是:

      $(CXX) $(CFLAGS) -c -o $@ $<
      

      如果你希望在編譯過程中添加特定的命令(例如輸出編譯信息、使用特定的編譯器選項等),則需要自定義模式規則:

      OBJS = main.o math.o
      TARGET = app
      
      $(TARGET): $(OBJS)
      	$(CXX) -o $@ $^
      
      # 模式規則
      %.o: %.cpp
      	@echo "Compiling $<..."
      	$(CXX) -c -o $@ $<
      
      clean:
      	rm -f *.o $(TARGET)
      

      執行make,輸出如下:

      Compiling main.cpp...
      g++ -c  -o main.o main.cpp
      Compiling math.cpp...
      g++ -c  -o math.o math.cpp
      g++ -o app main.o math.o

      自動生成依賴

      隱式規則和模式規則,這兩種規則都可以解決自動把.c文件編譯成.o文件,但都無法解決.c文件依賴.h文件的問題。用編譯器自動生成依賴流程:

      • 對每個.c(或.cpp)文件,生成對應的依賴文件(比如main.d),里面記錄該源文件依賴了哪些頭文件。

      • Makefile通過include包含這些.d文件。

      • 當頭文件修改時,make發現依賴變化,會自動重新編譯對應的.c文件。

      # 列出所有 .cpp 文件
      SRCS = $(wildcard *.cpp)
      
      # 根據 SRCS 生成 .o 文件列表
      OBJS = $(SRCS:.cpp=.o)
      
      # 根據 SRCS 生成 .d 文件列表(依賴文件)
      DEPS = $(SRCS:.cpp=.d)
      
      # 目標可執行文件名
      TARGET = app
      
      # 默認目標,鏈接所有目標文件生成可執行文件
      $(TARGET): $(OBJS)
      	$(CXX) -o $@ $^
      
      # 生成依賴文件 *.d(使用 g++ 的 -MM 生成依賴)
      %.d: %.cpp
      	rm -f $@; \
      	$(CXX) -MM $< > $@.tmp; \
      	sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.tmp > $@; \
      	rm -f $@.tmp
      
      # 模式規則:編譯 .cpp 文件生成 .o 文件
      %.o: %.cpp
      	$(CXX) -c -o $@ $<
      
      # 清理目標文件、依賴文件和可執行文件
      clean:
      	rm -rf *.o *.d $(TARGET)
      
      # 引入所有自動生成的依賴文件
      -include $(DEPS)

      執行make,輸出如下:

      rm -f main.d; \
      g++ -MM main.cpp > main.d.tmp; \
      sed 's,\(main\)\.o[ :]*,\1.o main.d : ,g' < main.d.tmp > main.d; \
      rm -f main.d.tmp
      rm -f math.d; \
      g++ -MM math.cpp > math.d.tmp; \
      sed 's,\(math\)\.o[ :]*,\1.o math.d : ,g' < math.d.tmp > math.d; \
      rm -f math.d.tmp
      g++ -c -o math.o math.cpp
      g++ -c -o main.o main.cpp
      g++ -o app math.o main.o
      

      通過include $(DEPS)我們引入math.dmain.d文件,但是這兩個文件一開始并不存在,不過,make通過模式規則匹配到%.d: %.c,這就給了我們一個機會,在這個模式規則內部,用cc -MM命令外加sed.d文件創建出來。此時改動math.h,再次運行make,可以觸發main.cpp的編譯。

      進一步的把源碼文件(src目錄)和生成的中間文件(如.o.d文件)分開放,比如把源代碼放 src/,把編譯生成的文件放 build/ 目錄。

      # 創建 src 目錄
      mkdir -p src
      
      # 移動源文件到 src/
      mv main.cpp src/
      mv math.cpp src/
      mv math.h src/
      

      這樣目錄結構就會變成:

      my_project/
      ├── Makefile
      ├── src/
      │   ├── main.c
      │   ├── math.c
      │   └── math.h

      然后更改Makefile

      # 源文件目錄
      SRCDIR = ./src
      
      # 生成文件目錄
      BUILDDIR = ./build
      
      # 查找所有 src 目錄下的 .cpp 文件
      SRCS = $(wildcard $(SRCDIR)/*.cpp)
      
      # 將 src/*.cpp 替換成 build/*.o
      OBJS = $(patsubst $(SRCDIR)/%.cpp, $(BUILDDIR)/%.o, $(SRCS))
      
      # 依賴文件列表 build/*.d
      DEPS = $(patsubst $(SRCDIR)/%.cpp, $(BUILDDIR)/%.d, $(SRCS))
      
      # 目標可執行文件名
      TARGET = $(BUILDDIR)/app
      
      # 默認目標:鏈接所有目標文件生成可執行文件
      $(TARGET): $(OBJS)
      	$(CXX) -o $@ $^
      
      # 生成依賴文件 build/%.d
      $(BUILDDIR)/%.d: $(SRCDIR)/%.cpp | $(BUILDDIR)
      	@rm -f $@; \
      	$(CXX) -MM $< > $@.tmp; \
      	sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.tmp > $@; \
      	rm -f $@.tmp
      
      # 編譯 .cpp 文件生成 .o 文件
      $(BUILDDIR)/%.o: $(SRCDIR)/%.cpp | $(BUILDDIR)
      	$(CXX) -c -o $@ $<
      
      # 創建生成文件目錄
      $(BUILDDIR):
      	mkdir -p $(BUILDDIR)
      
      # 清理所有編譯生成的文件和可執行文件
      clean:
      	rm -rf $(BUILDDIR) $(TARGET)
      
      # 包含所有依賴文件
      -include $(DEPS)
      

      再執行make,得到輸出

      g++ -o build/app build/math.o build/main.o

      補充:編譯型語言 vs 解釋型語言

      C++ 屬于典型的編譯型語言:源代碼需要經過完整的預處理、編譯、匯編和鏈接,最終生成二進制可執行文件。Python屬于解釋型語言:源代碼通過解釋器(Interpreter逐行讀取、逐行轉換為機器碼并執行,無需生成獨立的可執行文件,執行時必須依賴解釋器環境。

       C++(編譯型語言)Python(解釋型語言)
      執行方式 先編譯為可執行文件再運行 逐行解釋執行
      運行速度 通常較快,接近機器碼執行速度 通常較慢,解釋執行效率低
      依賴環境 不依賴運行時解釋器,僅需操作系統支持 運行時必須安裝 Python 解釋器
      平臺移植性 需針對目標平臺重新編譯 高,只要有解釋器即可運行
      內存管理 程序員手動分配和釋放內存(使用 new/delete 或智能指針) 自動內存管理,內置垃圾回收機制(Garbage Collection)
      類型系統 靜態類型,變量類型在編譯時確定,類型檢查嚴格 動態類型,變量類型在運行時確定,更靈活但易出錯
      適合的應用場景 高性能要求場景,如系統開發、圖形處理、游戲引擎 快速開發、腳本、數據分析、Web、人工智能等領域

       

       

      參考:

      1. Makefile教程

      posted @ 2025-07-05 14:25  灣仔碼農  閱讀(129)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 一区二区视频观看在线| 亚洲一区二区| 亚洲综合色网一区二区三区| 日本中文字幕有码在线视频| 日韩国产成人精品视频| 国产精品亚洲а∨天堂2021| 四虎永久在线精品8848a| 国产精品久久久久7777| 欧美丰满熟妇xxxx性| 国产一区二区在线有码| 高级艳妇交换俱乐部小说| 国产高清不卡视频| 人妻精品人妻无码一区二区三区| 撕开奶罩揉吮奶头高潮av| 亚洲最大成人美女色av| 瑞金市| 色吊a中文字幕一二三区| 国产精品午夜精品福利| 国产成人无码A区在线观| 国产极品粉嫩尤物一线天| 欧美亚洲综合成人a∨在线| 91精品91久久久久久| 久激情内射婷内射蜜桃| 亚洲天堂一区二区成人在线| 国产一区二区高清不卡| 亚洲国产超清无码专区| 女人香蕉久久毛毛片精品| 国产亚洲欧美日韩在线一区| AV秘 无码一区二| 亚洲国产精品无码久久久秋霞1| 欧美精品18videosex性欧美| 久久蜜臀av一区三区| 久久综合九色综合97欧美| 亚洲αⅴ无码乱码在线观看性色 | 中文字幕无码av不卡一区| 日韩本精品一区二区三区| 欧美v国产v亚洲v日韩九九| 伊伊人成亚洲综合人网香| 免费看久久妇女高潮a| 亚洲精品精华液一区二区| 日本一卡二卡不卡视频查询|