Các tùy chọn dòng lệnh GCC không phổ biến nhưng hữu ích - phần 2

theanh

Administrator
Nhân viên
Trình biên dịch gcc cung cấp một danh sách các tùy chọn dòng lệnh dường như vô tận. Tất nhiên, không ai sử dụng hoặc có chuyên môn về tất cả chúng, nhưng có một số tùy chọn mà mọi người dùng gcc nên - nếu không muốn nói là bắt buộc - biết. Trong khi một số trong số chúng được sử dụng phổ biến, một số khác hơi ít phổ biến nhưng không kém phần hữu ích.

Trong loạt bài viết này, chúng tôi sẽ tập trung vào một số tùy chọn dòng lệnh gcc ít phổ biến nhưng hữu ích và đã đề cập đến một số tùy chọn trong số chúng ở phần 1.

Nếu bạn nhớ lại, ở phần đầu của phần đầu tiên trong loạt bài hướng dẫn này, tôi đã đề cập ngắn gọn rằng tùy chọn -Wall mà các nhà phát triển thường sử dụng để tạo cảnh báo không bao gồm một số cảnh báo cụ thể. Nếu bạn không biết về những cảnh báo này và không biết cách bật chúng, đừng lo lắng, vì chúng tôi sẽ giải thích chi tiết tất cả trong bài viết này.

Ngoài ra, chúng tôi cũng sẽ đề cập đến tùy chọn gccwarning liên quan đến các biến dấu phẩy động, cũng như cách quản lý tốt hơn các tùy chọn dòng lệnh gcc nếu danh sách ngày càng dài.

Nhưng trước khi tiếp tục, hãy nhớ rằng tất cả các ví dụ, lệnh và hướng dẫn được đề cập trong hướng dẫn này đều đã được thử nghiệm trên Ubuntu 16.04 LTS và phiên bản gcc mà chúng tôi sử dụng là 5.4.0.


Bật các cảnh báo không được -Wall bao phủ​

Mặc dù tùy chọn -Wall của trình biên dịch gcc bao phủ hầu hết các cờ cảnh báo, nhưng vẫn có một số cờ vẫn bị vô hiệu hóa. Để bật chúng, hãy sử dụng tùy chọn -Wextra.

Ví dụ, hãy xem đoạn mã sau:
Mã:
#include 
#include 
int main()
{
 int i=0;
 /* ...
 một số mã ở đây 
 ...
 */
 
 if(i);
 return 1;
 return 0; 
}
Tôi vô tình đặt dấu chấm phẩy sau điều kiện 'if'. Bây giờ, khi mã được biên dịch bằng lệnh gcc sau, không có cảnh báo nào được tạo ra.
Mã:
gcc -Wall test.c -o test
Nhưng khi tùy chọn -Wextra được sử dụng:
Mã:
gcc -Wall -Wextra test.c -o test
Một cảnh báo được tạo ra:
Mã:
test.c: Trong hàm ‘main’:
test.c:10:8: cảnh báo: đề xuất dấu ngoặc nhọn xung quanh phần thân rỗng trong câu lệnh ‘if’ [-Wempty-body]
 if(i);
Như cảnh báo được hiển thị ở trên, tùy chọn -Wextra đã bật cờ -Wempty-body bên trong, cờ này sẽ phát hiện mã đáng ngờ và đưa ra cảnh báo. Sau đây là danh sách đầy đủ các cờ cảnh báo được bật bởi tùy chọn này:

-Wclobbered, -Wempty-body, -Wignored-qualifiers, -Wmissing-field-initializers, -Wmissing-parameter-type (chỉ C),-Wold-style-declaration (chỉ C), -Woverride-init, -Wsign-compare, -Wtype-limits, -Wuninitialized, -Wunused-parameter (chỉ với-Wunused hoặc -Wall), và -Wunused-but-set-parameter (chỉ với -Wunused hoặc -Wall).

Nếu bạn muốn tìm hiểu các cờ được đề cập ở trên có chức năng gì, hãy truy cập trang hướng dẫn của gcc.

Tiếp theo, tùy chọn -Wextra cũng đưa ra cảnh báo trong các trường hợp sau:
  • Một con trỏ được so sánh với số nguyên không với <, <=, > hoặc >=
  • (Chỉ C++) Cả một enumerator và một non-enumerator đều xuất hiện trong một
    biểu thức điều kiện.
  • (Chỉ C++) Các cơ sở ảo mơ hồ.
  • (Chỉ C++) Chỉ số hóa một mảng đã được khai báo
    register.
  • (Chỉ C++) Lấy địa chỉ của một biến đã được
    khai báo register.
  • (Chỉ C++) Một lớp cơ sở không được khởi tạo trong
    hàm tạo bản sao của lớp dẫn xuất.

Bật cảnh báo cho các giá trị dấu phẩy động trong so sánh vốn chủ sở hữu​

Như bạn có thể đã biết, người ta không bao giờ nênkiểm tra xem các giá trị dấu phẩy động có bằng nhau chính xác hay không (không biết điều này - hãy đọc thefloating-point Câu hỏi thường gặp liên quan đến so sánh tại đây). Nhưng ngay cả khi bạn vô tình làm điều này, trình biên dịch gcc có đưa ra bất kỳ cảnh báo hoặc lỗi nào không? Hãy cùng kiểm tra:

Sau đây là mã so sánh các biến dấu phẩy động bằng toán tử ==:
Mã:
#include

void compare(float x, float y)
{
 if(x == y)
 {
 printf("\n EQUAL \n");
 }
}


int main(void)
{
 compare(1.234, 1.56789);
 
 return 0; 
}
Và đây là lệnh gcc (chứa cả tùy chọn -Wall và -Wextra) được sử dụng để biên dịch mã này:
Mã:
gcc -Wall -Wextra test.c -o test
Thật đáng buồn là lệnh trên không đưa ra bất kỳ cảnh báo nào liên quan đến so sánh dấu phẩy động. Nhìn nhanh vào trang hướng dẫn của GCC cho thấy có một tùy chọn chuyên dụng -Wfloat-equal nên được sử dụng trong các tình huống này.

Đây là lệnh chứa tùy chọn này:
Mã:
gcc -Wall -Wextra -Wfloat-equal test.c -o test
Và sau đây là đầu ra mà nó tạo ra:
Mã:
test.c: Trong hàm ‘compare’:
test.c:5:10: cảnh báo: so sánh dấu phẩy động với == hoặc != là không an toàn [-Wfloat-equal]
 if(x == y)
Vì vậy, như bạn có thể thấy trong đầu ra ở trên, tùy chọn -Wfloat-equal buộc gcc phải tạo cảnh báo liên quan đến so sánh dấu phẩy động.

Đây là nội dung trang hướng dẫn của gccnói về tùy chọn này:
Mã:
Ý tưởng đằng sau điều này là đôi khi sẽ thuận tiện (cho lập trình viên) khi coi các giá trị dấu phẩy động là các giá trị xấp xỉ với các số thực vô cùng chính xác. Nếu bạn đang làm điều này, thì bạn cần tính toán (bằng cách phân tích mã hoặc theo một cách nào đó khác) lỗi tối đa hoặc lỗi tối đa có thể xảy ra mà phép tính đưa ra và cho phép lỗi này khi thực hiện so sánh (và khi tạo ra đầu ra, nhưng đó là một vấn đề khác). Cụ thể, thay vì kiểm tra tính bằng nhau, bạn nên kiểm tra xem hai giá trị có phạm vi chồng lấn hay không; và điều này được thực hiện bằng các toán tử quan hệ, vì vậy các phép so sánh bằng nhau có thể bị nhầm lẫn.

Cách quản lý tốt hơn các tùy chọn dòng lệnh gcc​

Nếu danh sách các tùy chọn dòng lệnh mà bạn đang sử dụng trong lệnh gcc của mình ngày càng lớn và khó quản lý, thì bạn có thể đưa danh sách đó vào một tệp văn bản và truyền tên tệp đó làm đối số cho lệnh gcc. Đối với điều này, bạn sẽ phải sử dụng tùy chọn dòng lệnh @file.

Ví dụ, nếu lệnh gcc của bạn là:
Mã:
gcc -Wall -Wextra -Wfloat-equal test.c -o test
Sau đó, bạn có thể đặt ba tùy chọn liên quan đến cảnh báo vào một tệp có tên là 'gcc-options':
Mã:
$ cat gcc-options 
-Wall -Wextra -Wfloat-equal
Và lệnh gcc của bạn trở nên bớt lộn xộn và dễ quản lý hơn:
Mã:
gcc @gcc-options test.c -o test
Đây là những gì trang hướng dẫn gcc nói về @file:
Mã:
Đọc các tùy chọn dòng lệnh từ tệp. Các tùy chọn đã đọc được chèn vào vị trí của tùy chọn @file ban đầu. Nếu tệp không tồn tại hoặc không thể đọc được, thì tùy chọn sẽ được xử lý theo nghĩa đen và không bị xóa.

Các tùy chọn trong tệp được phân tách bằng khoảng trắng. Có thể đưa ký tự khoảng trắng vào tùy chọn bằng cách bao quanh toàn bộ tùy chọn trong dấu ngoặc đơn hoặc dấu ngoặc kép. Bất kỳ ký tự nào (bao gồm dấu gạch chéo ngược) có thể được đưa vào bằng cách thêm tiền tố dấu gạch chéo ngược vào ký tự cần đưa vào. Bản thân tệp có thể chứa các tùy chọn @file bổ sung; bất kỳ tùy chọn nào như vậy sẽ được xử lý đệ quy.

Kết luận​

Vì vậy, chúng tôi đã đề cập đến tổng cộng 5 tùy chọn dòng lệnh gcc không phổ biến nhưng hữu ích trong loạt hướng dẫn này: -save-temps, -g, -Wextra, -Wfloat-equal và @file. Hãy dành thời gian thực hành từng tùy chọn và đừng quên xem qua tất cả các chi tiết mà trang hướng dẫn gcc cung cấp về chúng.

Bạn có biết hoặc sử dụng các tùy chọn dòng lệnh gcc hữu ích khác như vậy không và muốn chia sẻ chúng với mọi người? Hãy để lại tất cả các chi tiết trong phần bình luận bên dưới.
 
Back
Bên trên