Quá trình biên dịch một chương trình C/C++

Tổng quan

Quá trình biên dịch là biến đổi mã mà con người hiểu thành định dạng máy tính hiểu được. Đối với ngôn ngữ lập trình C/C++, quá trình biên dịch bao gồm bốn bước: Preprocessor, Compiler, Assembler và Linker.

Compilation process in C/C++

Quá trình Biên dịch là gì?

Trước khi bắt đầu, chúng ta cùng xét một ví dụ sau: 

anh Hay chỉ biết nói tiếng Việt, chị Code lại chỉ biết nói tiếng Anh, mà bây giờ hai người đang muốn nói chuyện với nhau thì cần phải làm thế nào. Một cách đơn giản, một trong hai người có thể nhờ một người nào biết cả tiếng Việt và tiếng Anh để dịch lại những gì hai người nói. Quá trình này được gọi là "quá trình dịch thuật"

Trong lập trình cũng tương tự, sẽ có một quá trình để chuyển đổi mã mà con người hiểu được sang mã mà máy tính hiểu được, gọi là quá trình biên dịch.

Trong ngôn ngữ lập trình C và lập trình C++, có bốn giai đoạn để biên dịch chương trình C/C++ sang file thực thi.

  1. Preprocessor (Tiền xử lý)
  2. Compiler
  3. Assembler
  4. Linker
Các bạn có thể xem video sau hoặc bỏ qua video và đọc tiếp để hiểu rõ hơn về bốn giai đoạn trong quá trình biên dịch.

Chuẩn bị Code

Trước khi tìm hiểu chúng ta cùng chuẩn bị các file Code như sau:
  • hello.c
#include "sum.h"
#define THIS_YEAR 2023
int main() {
	// This is a comment
#if 1
	int last_year = THIS_YEAR - 1;
#else
	int next_year = THIS_YEAR + 1;
#endif
	int a = 0, b = 0;
	int c = sum(a, b);
	return 0;
}
  • sum.c
#include "sum.h"
int sum(int a, int b) {
	return a + b;
}
  • sum.h
int sum(int a, int b);

1. Preprocessor

Preprocessor (hay Tiền xử lý) là bước đầu tiên trong quá trình biên dịch, có bốn nhiệm vụ chính sau:
  • Xóa Comment
  • Mở rộng Macro
  • Mở rộng các file include
  • Biên dịch câu lệnh điều kiện (kiểu #if ...)
Ví dụ chạy câu lệnh sau để xử lý file hello.c
gcc -E hello.c -o hello.i

Kết quả của quá trình này là filename.i hoặc filename.ii (trong ví dụ này là hello.i). Hãy cùng xem trong file hello.i có gì.
# 0 "hello.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "hello.c"
# 1 "sum.h" 1
int sum(int a, int b);
# 2 "hello.c" 2
int main() {
    int last_year = 2023 - 1;
    int a = 0, b = 0;
    int c = sum(a, b);
  return 0;
}

2. Compiler

Bước tiếp theo là biên dịch filename.i thành một ngôn ngữ bậc thấp hơn là Assembly. Câu lệnh sau đây sẽ thực hiện biên dịch file hello.i thành file Assembly Code
gcc -S hello.i -o hello.s

Kết quả của quá trình này là filename.s (file Assembly Code)

3. Assembler

Trong bước này, filename,s được sử dụng làm đầu vào và được trình biên dịch chuyển thành filename.o (Object file) . File này chứa ngôn ngữ máy.
Câu lệnh sau sẽ thực hiện biên dịch file hello.s thành hello.o
gcc -c hello.s -o hello.o

4.Linker

Bước này sẽ thực hiện liên kết các file object (file .o) được tạo ở trên, cùng với các file thư viện bên ngoài (.lib, .a, ...) thành một file thực thi duy nhất.
Ví dụ nếu bạn chạy lệnh sau:
gcc -o hello.o
Một lỗi liên quan đến quá trình Linker sẽ xuất hiện. Lỗi này là do trong file hello.c, mình có sử dụng một hàm sum(). Nhưng hàm này lại được khai báo trong file sum.c, mà trong câu lệnh trên không có file object của sum.c nên trình biên dịch sẽ không biết lấy hàm sum() ở đâu.
Để giải quyết chúng ta cần biên dịch file sum.c thành sum.o và thực hiện lệnh sau.
gcc -o hello.o sum.o

Tạm kết

Hi vọng, qua bài viết này bạn có thể hiểu được quá trình biên dịch một chương trình C/C++ sang file thực thi diễn ra như thế nào.

Mới hơn Cũ hơn