Đối với bối cảnh, tôi là một nhà phát triển Clang làm việc tại Google. Tại Google, chúng tôi đã giới thiệu chẩn đoán của Clang cho (về cơ bản) tất cả các nhà phát triển C ++ của chúng tôi và chúng tôi cũng coi các cảnh báo của Clang là lỗi. Là cả một nhà phát triển Clang và một trong những người sử dụng chẩn đoán Clang lớn hơn, tôi sẽ cố gắng làm sáng tỏ những lá cờ này và cách sử dụng chúng. Lưu ý rằng mọi thứ tôi mô tả đều có thể áp dụng chung cho Clang và không dành riêng cho C, C ++ hoặc Objective-C.
Phiên bản TL; DR: Vui lòng sử dụng -Wall
và -Werror
tối thiểu trên bất kỳ mã mới nào bạn đang phát triển. Chúng tôi (các nhà phát triển trình biên dịch) thêm cảnh báo ở đây vì lý do chính đáng: họ tìm thấy lỗi. Nếu bạn tìm thấy một cảnh báo bắt lỗi cho bạn, hãy bật nó lên. Hãy thử -Wextra
cho một loạt các ứng cử viên tốt ở đây. Nếu một trong số chúng quá ồn để bạn sử dụng có lợi nhuận, hãy báo lỗi . Nếu bạn viết mã có lỗi "rõ ràng" nhưng trình biên dịch đã không cảnh báo về nó, hãy báo lỗi.
Bây giờ cho phiên bản dài. Đầu tiên một số nền tảng về nhóm cờ cảnh báo. Có rất nhiều "nhóm" cảnh báo ở Clang (và ở một mức độ hạn chế trong GCC). Một số có liên quan đến cuộc thảo luận này:
- Theo mặc định: Những cảnh báo này luôn được bật trừ khi bạn vô hiệu hóa chúng một cách rõ ràng.
-Wall
: Đây là những cảnh báo rằng các nhà phát triển có độ tin cậy cao về cả giá trị của họ và tỷ lệ dương tính giả thấp.
-Wextra
: Đây là những cảnh báo được cho là có giá trị và âm thanh (nghĩa là chúng không có lỗi), nhưng chúng có thể có tỷ lệ dương tính giả cao hoặc phản đối triết học phổ biến.
-Weverything
: Đây là một nhóm điên rồ, theo nghĩa đen cho phép mọi
cảnh báo trong Clang. Đừng sử dụng mã này trên mã của bạn. Nó được dành riêng cho các nhà phát triển Clang hoặc để khám phá những cảnh báo tồn tại .
Có hai tiêu chí chính được đề cập ở trên hướng dẫn cảnh báo đi đâu trong Clang và hãy làm rõ những điều này thực sự có ý nghĩa gì. Đầu tiên là giá trị tiềm năng
của một sự xuất hiện cụ thể của cảnh báo. Đây là lợi ích mong đợi cho người dùng (nhà phát triển) khi cảnh báo kích hoạt và xác
định chính xác một vấn đề với mã.
Tiêu chí thứ hai là ý tưởng về các báo cáo dương tính giả . Đây là những tình huống cảnh báo kích hoạt mã, nhưng vấn đề tiềm ẩn được trích dẫn trên thực tế không xảy ra do bối cảnh hoặc một số ràng buộc khác của chương trình. Các mã được cảnh báo về là thực sự hành xử chính xác. Điều này đặc biệt tệ khi cảnh báo không bao giờ có ý định bắn vào mẫu mã đó. Thay vào đó, đó là một thiếu sót trong việc thực hiện cảnh báo khiến nó bắn ở đó.
Đối với các cảnh báo Clang, giá trị được yêu cầu là về tính chính xác , không phải về phong cách, hương vị hoặc quy ước mã hóa. Điều này giới hạn tập hợp các cảnh báo có sẵn, loại trừ các cảnh báo được yêu cầu như cảnh báo bất cứ khi nào {}
s không được sử dụng xung quanh phần thân của một if
tuyên bố. Clang cũng rất không khoan dung với dương tính giả . Không giống như hầu hết các trình biên dịch khác, nó sẽ sử dụng nhiều nguồn thông tin đáng kinh ngạc để cắt xén các lỗi tích cực bao gồm cả cách viết chính xác của cấu trúc, sự hiện diện hoặc không có thêm '()', phôi hoặc thậm chí là các macro tiền xử lý!
Bây giờ chúng ta hãy lấy một số cảnh báo ví dụ trong thế giới thực từ Clang và xem cách chúng được phân loại. Đầu tiên, cảnh báo bật mặc định:
% nl x.cc
1 class C { const int x; };
% clang -fsyntax-only x.cc
x.cc:1:7: warning: class 'C' does not declare any constructor to initialize its non-modifiable members
class C { const int x; };
^
x.cc:1:21: note: const member 'x' will never be initialized
class C { const int x; };
^
1 warning generated.
Ở đây không có cờ được yêu cầu để có được cảnh báo này. Lý do là đây là mã không bao giờ thực sự chính xác, mang lại giá trị cảnh báo cao và cảnh báo chỉ bắn vào mã mà Clang có thể chứng minh rơi vào nhóm này, cho tỷ lệ dương tính giả .
% nl x2.cc
1 int f(int x_) {
2 int x = x;
3 return x;
4 }
% clang -fsyntax-only -Wall x2.cc
x2.cc:2:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
int x = x;
~ ^
1 warning generated.
Clang yêu cầu -Wall
cờ cho cảnh báo này. Lý do là có một số lượng mã không tầm thường đã sử dụng (tốt hoặc xấu) mẫu mã mà chúng tôi đang cảnh báo về việc cố tình tạo ra một giá trị chưa được khởi tạo. Về mặt triết học, tôi thấy không có điểm nào trong vấn đề này, nhưng nhiều người khác không đồng ý và thực tế về sự khác biệt này trong quan điểm là điều thúc đẩy cảnh báo dưới
-Wall
lá cờ. Nó vẫn có giá trị rất cao và tỷ lệ dương tính giả rất thấp
, nhưng trên một số cơ sở mã hóa, nó không phải là khởi đầu.
% nl x3.cc
1 void g(int x);
2 void f(int arr[], unsigned int size) {
3 for (int i = 0; i < size; ++i)
4 g(arr[i]);
5 }
% clang -fsyntax-only -Wextra x3.cc
x3.cc:3:21: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
for (int i = 0; i < size; ++i)
~ ^ ~~~~
1 warning generated.
Cảnh báo này yêu cầu -Wextra
cờ. Lý do là có
những cơ sở mã rất lớn trong đó dấu hiệu khớp sai trên các phép so sánh là cực kỳ phổ biến. Mặc dù cảnh báo này không tìm thấy một số lỗi, nhưng xác suất mã là lỗi khi người dùng viết nó trung bình khá thấp. Kết quả là tỷ lệ dương tính giả cực kỳ cao . Tuy nhiên, khi có một lỗi trong chương trình do các quy tắc quảng cáo lạ, nó thường cực kỳ tinh tế khi đưa ra cảnh báo này
khi nó gắn cờ một lỗi có giá trị tương đối cao . Kết quả là, Clang cung cấp nó và phơi nó dưới một lá cờ.
Thông thường, cảnh báo không sống lâu bên ngoài -Wextra
cờ. Clang rất cố gắng để không thực hiện các cảnh báo không thấy việc sử dụng và kiểm tra thường xuyên. Các cảnh báo bổ sung được bật bởi -Weverything
thường là các cảnh báo dưới sự phát triển tích cực hoặc với các lỗi hoạt động. Hoặc chúng sẽ được cố định và đặt dưới cờ thích hợp, hoặc chúng nên được gỡ bỏ.
Bây giờ chúng ta đã hiểu cách thức những thứ này hoạt động với Clang, chúng ta hãy thử quay lại câu hỏi ban đầu: bạn nên bật cảnh báo nào cho sự phát triển của mình? Câu trả lời là, không may, điều đó phụ thuộc. Xem xét các câu hỏi sau để giúp xác định cảnh báo nào hoạt động tốt nhất cho tình huống của bạn.
- Bạn có quyền kiểm soát tất cả các mã của bạn, hoặc một số mã bên ngoài?
- Mục tiêu của bạn là gì? Bắt lỗi, hoặc viết mã tốt hơn?
- Sự khoan dung dương tính giả của bạn là gì? Bạn có sẵn sàng viết thêm mã để cảnh báo im lặng một cách thường xuyên không?
Đầu tiên và quan trọng nhất, nếu bạn không kiểm soát mã, đừng thử bật thêm cảnh báo ở đó. Hãy chuẩn bị để tắt một số. Có rất nhiều mã xấu trên thế giới và bạn có thể không sửa được tất cả. Được thôi. Làm việc để tìm cách tập trung nỗ lực của bạn vào mã bạn kiểm soát.
Tiếp theo, tìm ra những gì bạn muốn từ các cảnh báo của bạn. Điều này là khác nhau cho những người khác nhau. Clang sẽ cố gắng cảnh báo mà không có bất kỳ tùy chọn nào đối với các lỗi nghiêm trọng hoặc các mẫu mã mà chúng tôi có tiền lệ từ lâu cho thấy tỷ lệ lỗi là rất cao. Bằng cách cho phép -Wall
bạn sẽ có được một loạt các cảnh báo tích cực hơn nhằm vào các lỗi phổ biến nhất mà các nhà phát triển Clang đã quan sát thấy trong mã C ++. Nhưng với cả hai
tỷ lệ dương tính giả này vẫn còn khá thấp.
Cuối cùng, nếu bạn hoàn toàn sẵn sàng im lặng * dương tính giả * mỗi lần, hãy tiếp tục -Wextra
. Lỗi tệp nếu bạn nhận thấy các cảnh báo đang bắt rất nhiều lỗi thực sự, nhưng có lỗi tích cực ngớ ngẩn hoặc vô nghĩa. Chúng tôi liên tục làm việc để tìm cách đưa ngày càng nhiều logic tìm kiếm lỗi -Wextra
vào -Wall
nơi chúng tôi có thể tránh được những lỗi tích cực.
Nhiều người sẽ thấy rằng không có lựa chọn nào trong số này là phù hợp với họ. Tại Google, chúng tôi đã -Wall
tắt một số cảnh báo do có rất nhiều mã hiện có vi phạm cảnh báo. Chúng tôi cũng đã bật một số cảnh báo rõ ràng, mặc dù chúng không được kích hoạt bởi -Wall
vì chúng có giá trị đặc biệt cao đối với chúng tôi. Số dặm của bạn sẽ thay đổi, nhưng có thể sẽ thay đổi theo những cách tương tự. Nó thường có thể tốt hơn nhiều để kích hoạt một vài cảnh báo quan trọng hơn là tất cả
-Wextra
.
Tôi sẽ khuyến khích tất cả mọi người bật -Wall
cho bất kỳ mã không kế thừa. Đối với mã mới, các cảnh báo ở đây hầu như luôn có giá trị và thực sự làm cho trải nghiệm phát triển mã tốt hơn. Ngược lại, tôi sẽ khuyến khích mọi người
không kích hoạt cờ ngoài -Wextra
. Nếu bạn tìm thấy một cảnh báo Clang -Wextra
không bao gồm nhưng điều đó chứng tỏ tất cả đều có giá trị đối với bạn, chỉ cần gửi một lỗi và chúng tôi có thể đưa nó vào -Wextra
. Việc bạn có bật một số tập hợp cảnh báo một cách rõ ràng hay không -Wextra
sẽ phụ thuộc rất nhiều vào mã của bạn, kiểu mã hóa của bạn và việc duy trì danh sách đó có dễ hơn sửa chữa mọi thứ mà không bị phát hiện hay không -Wextra
.
Trong danh sách cảnh báo của OP (bao gồm cả hai -Wall
và -Wextra
) chỉ những cảnh báo sau không thuộc hai nhóm đó (hoặc được bật theo mặc định). Nhóm đầu tiên nhấn mạnh tại sao sự phụ thuộc quá mức vào các cờ cảnh báo rõ ràng có thể là xấu: không ai trong số này thậm chí được thực hiện trong Clang! Chúng chỉ được chấp nhận trên dòng lệnh để tương thích với GCC.
-Wbad-function-cast
-Wdeclaration-after-statement
-Wmissing-format-attribute
-Wmissing-noreturn
-Wnested-externs
-Wnewline-eof
-Wold-style-definition
-Wredundant-decls
-Wsequence-point
-Wstrict-prototypes
-Wswitch-default
Nhóm cảnh báo không cần thiết tiếp theo trong danh sách ban đầu là những cảnh báo dư thừa với những người khác trong danh sách đó:
-Wformat-nonliteral
-- Tập hợp con của -Wformat=2
-Wshorten-64-to-32
-- Tập hợp con của -Wconversion
-Wsign-conversion
-- Tập hợp con của -Wconversion
Ngoài ra còn có một lựa chọn các cảnh báo khác nhau hơn về mặt phân loại. Chúng xử lý các biến thể phương ngữ ngôn ngữ hơn là mã lỗi hoặc không lỗi. Ngoại trừ -Wwrite-strings
, tất cả đều là những cảnh báo cho các phần mở rộng ngôn ngữ do Clang cung cấp. Việc Clang có cảnh báo về việc sử dụng chúng hay không phụ thuộc vào mức độ phổ biến của phần mở rộng. Clang nhắm đến khả năng tương thích GCC, và trong nhiều trường hợp, nó giúp giảm bớt điều đó với các phần mở rộng ngôn ngữ ngầm được sử dụng rộng rãi. -Wwrite-strings
, như đã nhận xét về OP, là một cờ tương thích từ GCC thực sự thay đổi ngữ nghĩa chương trình. Tôi vô cùng hối tiếc về lá cờ này, nhưng chúng tôi phải hỗ trợ nó do di sản hiện có.
-Wfour-char-constants
-Wpointer-arith
-Wwrite-strings
Các tùy chọn còn lại thực sự cho phép cảnh báo thú vị tiềm năng là:
-Wcast-align
-Wconversion
-Wfloat-equal
-Wformat=2
-Wimplicit-atomic-properties
-Wmissing-declarations
-Wmissing-prototypes
-Woverlength-strings
-Wshadow
-Wstrict-selector-match
-Wundeclared-selector
-Wunreachable-code
Lý do mà những điều này không có trong -Wall
hoặc -Wextra
không luôn luôn rõ ràng. Đối với nhiều người trong số này, họ đang thực sự dựa trên cảnh báo GCC ( -Wconversion
,
-Wshadow
, vv) và như vậy Clang cố gắng bắt chước hành vi của GCC. Chúng tôi đang dần phá vỡ một số trong số này thành các cảnh báo hữu ích và tốt hơn. Những người sau đó có xác suất cao hơn để đưa nó vào một trong những nhóm cảnh báo cấp cao nhất. Điều đó nói rằng, để chọn trên một cảnh báo, -Wconversion
là quá rộng mà nó có thể sẽ vẫn riêng của mình "cấp cao nhất" loại trong tương lai gần. Một số cảnh báo khác mà GCC có nhưng có giá trị thấp và tỷ lệ dương tính giả cao có thể được chuyển xuống vùng đất không có người tương tự.
Các lý do khác khiến chúng không nằm trong một trong các thùng lớn hơn bao gồm các lỗi đơn giản, các vấn đề dương tính giả rất quan trọng và cảnh báo trong quá trình phát triển. Tôi sẽ xem xét việc nộp các lỗi cho những cái tôi có thể xác định. Cuối cùng tất cả chúng nên di chuyển vào một cờ xô lớn thích hợp hoặc bị xóa khỏi Clang.
Tôi hy vọng điều này làm rõ tình huống cảnh báo với Clang và cung cấp một số thông tin chi tiết cho những người đang cố gắng chọn một bộ cảnh báo cho việc sử dụng của họ hoặc sử dụng của công ty họ.