Lệnh g++ trong Linux

Giới thiệu

Trong lab này, chúng ta sẽ khám phá lệnh g++ của Linux và các ứng dụng thực tế của nó. Chúng ta sẽ bắt đầu bằng cách tìm hiểu những điều cơ bản của lệnh g++, vốn là trình biên dịch GNU C++ được sử dụng để biên dịch mã nguồn C++ thành các chương trình có thể thực thi. Sau đó, chúng ta sẽ biên dịch một chương trình C++ đơn giản bằng g++ và khám phá các cờ trình biên dịch và các tùy chọn tối ưu hóa khác nhau. Lab này nhằm mục đích cung cấp một sự hiểu biết toàn diện về lệnh g++ và việc sử dụng nó trong phát triển phần mềm.

Tìm hiểu những điều cơ bản của lệnh g++

Trong bước này, chúng ta sẽ tìm hiểu những điều cơ bản của lệnh g++, vốn là trình biên dịch GNU C++. Lệnh g++ được sử dụng để biên dịch mã nguồn C++ thành một chương trình có thể thực thi.

Đầu tiên, hãy kiểm tra phiên bản của g++ được cài đặt trong container Docker Ubuntu 22.04 của chúng ta:

g++ --version

Ví dụ đầu ra:

g++ (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Lệnh g++ có một số tùy chọn quan trọng mà bạn có thể sử dụng để kiểm soát quá trình biên dịch. Một số tùy chọn thường được sử dụng là:

  • -c: Biên dịch hoặc hợp ngữ các tệp nguồn, nhưng không liên kết.
  • -o <output>: Đặt tên cho tệp đầu ra.
  • -g: Tạo thông tin gỡ lỗi trong tệp đầu ra.
  • -Wall: Bật tất cả các thông báo cảnh báo.
  • -Wextra: Bật các thông báo cảnh báo bổ sung.
  • -std=c++11 (hoặc c++14, c++17, v.v.): Chỉ định tiêu chuẩn C++ để sử dụng.
  • -O0, -O1, -O2, -O3: Đặt mức tối ưu hóa.

Bây giờ, hãy thử biên dịch một chương trình C++ đơn giản bằng lệnh g++:

cd ~/project
nano hello.cpp

Thêm mã sau vào tệp hello.cpp:

#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

Lưu tệp và thoát khỏi trình soạn thảo văn bản. Bây giờ, hãy biên dịch chương trình:

g++ -o hello hello.cpp

Điều này sẽ tạo một tệp thực thi có tên là hello trong thư mục hiện tại. Bạn có thể chạy chương trình như sau:

./hello

Ví dụ đầu ra:

Hello, World!

Biên dịch một chương trình C++ đơn giản bằng g++

Trong bước này, chúng ta sẽ tìm hiểu cách biên dịch một chương trình C++ đơn giản bằng lệnh g++.

Đầu tiên, hãy tạo một tệp C++ mới trong thư mục ~/project:

cd ~/project
nano simple.cpp

Thêm mã sau vào tệp simple.cpp:

#include <iostream>

int main() {
    int a = 10, b = 20;
    std::cout << "a + b = " << a + b << std::endl;
    return 0;
}

Lưu tệp và thoát khỏi trình soạn thảo văn bản.

Bây giờ, hãy biên dịch chương trình bằng lệnh g++:

g++ -o simple simple.cpp

Điều này sẽ tạo một tệp thực thi có tên là simple trong thư mục hiện tại. Bạn có thể chạy chương trình như sau:

./simple

Ví dụ đầu ra:

a + b = 30

Tùy chọn -o chỉ định tên của tệp đầu ra. Nếu bạn không sử dụng tùy chọn này, g++ sẽ tạo một tệp thực thi có tên là a.out theo mặc định.

Bạn cũng có thể thêm các cờ trình biên dịch bổ sung để kiểm soát quá trình biên dịch. Ví dụ: cờ -g sẽ bao gồm thông tin gỡ lỗi trong tệp nhị phân đã biên dịch, có thể hữu ích cho việc khắc phục sự cố:

g++ -g -o simple simple.cpp

Và các cờ -Wall-Wextra sẽ bật các thông báo cảnh báo bổ sung, có thể giúp bạn xác định các vấn đề tiềm ẩn trong mã của mình:

g++ -Wall -Wextra -o simple simple.cpp

Khám phá các cờ trình biên dịch g++ và Tối ưu hóa

Trong bước này, chúng ta sẽ khám phá thêm các cờ trình biên dịch g++ và tìm hiểu cách tối ưu hóa hiệu suất của các chương trình C++ của chúng ta.

Đầu tiên, hãy tạo một tệp C++ mới để thực hiện một phép tính đơn giản:

cd ~/project
nano optimize.cpp

Thêm mã sau vào tệp optimize.cpp:

#include <iostream>

int main() {
    int sum = 0;
    for (int i = 0; i < 1000000000; i++) {
        sum += i;
    }
    std::cout << "Sum: " << sum << std::endl;
    return 0;
}

Chương trình này tính tổng của 1 tỷ số nguyên đầu tiên.

Bây giờ, hãy biên dịch chương trình mà không có bất kỳ cờ tối ưu hóa nào:

g++ -o optimize optimize.cpp
time ./optimize

Ví dụ đầu ra:

Sum: 499999999500000000
real    0m1.123s
user    0m1.120s
sys     0m0.003s

Tiếp theo, hãy thử biên dịch chương trình với cờ tối ưu hóa -O2:

g++ -O2 -o optimize optimize.cpp
time ./optimize

Ví dụ đầu ra:

Sum: 499999999500000000
real    0m0.189s
user    0m0.185s
sys     0m0.003s

Như bạn có thể thấy, cờ tối ưu hóa -O2 cải thiện đáng kể hiệu suất của chương trình.

Bạn cũng có thể thử các mức tối ưu hóa khác, chẳng hạn như -O0 (không tối ưu hóa), -O1, -O3-Ofast. Mỗi cấp độ cung cấp các đánh đổi khác nhau giữa thời gian biên dịch, kích thước chương trình và tốc độ thực thi.

Một cờ hữu ích khác là -march=native, cờ này cho trình biên dịch biết tạo mã được tối ưu hóa cho kiến trúc CPU cụ thể của máy chủ. Điều này có thể cung cấp thêm những cải tiến về hiệu suất:

g++ -O2 -march=native -o optimize optimize.cpp
time ./optimize

Ví dụ đầu ra:

Sum: 499999999500000000
real    0m0.174s
user    0m0.170s
sys     0m0.003s

Cuối cùng, hãy khám phá cờ -ffast-math, cờ này cho phép tối ưu hóa dấu phẩy động tích cực. Cờ này có thể cải thiện đáng kể hiệu suất cho các chương trình sử dụng nhiều phép toán dấu phẩy động, nhưng nó cũng có thể gây ra một số mất mát về độ chính xác:

g++ -O2 -ffast-math -o optimize optimize.cpp
time ./optimize

Ví dụ đầu ra:

Sum: 499999999500000000
real    0m0.159s
user    0m0.155s
sys     0m0.003s

Như bạn có thể thấy, các cờ trình biên dịch khác nhau có thể có tác động đáng kể đến hiệu suất của các chương trình C++ của bạn. Điều quan trọng là phải thử nghiệm và tìm ra sự cân bằng phù hợp giữa tối ưu hóa, hiệu suất và độ chính xác cho trường hợp sử dụng cụ thể của bạn.

Tóm tắt

Trong lab này, chúng ta đã học những điều cơ bản về lệnh g++, vốn là trình biên dịch GNU C++. Chúng ta đã khám phá cách biên dịch một chương trình C++ đơn giản bằng g++ và kiểm tra các cờ trình biên dịch và tùy chọn tối ưu hóa khác nhau. Chúng ta đã đề cập đến việc biên dịch chương trình "Hello, World!" và một chương trình C++ phức tạp hơn, cũng như hiểu mục đích của các cờ trình biên dịch khác nhau như -c, -o, -g, -Wall, -Wextra, -std=c++11 và các mức tối ưu hóa -O0 đến -O3. Các bước này đã cung cấp một nền tảng vững chắc để làm việc với lệnh g++ và biên dịch các chương trình C++ trong môi trường Linux.

400+ câu lệnh phổ biến trong Linux