Trình biên dịch nên báo cáo lỗi và cảnh báo như thế nào?


11

Tôi không có kế hoạch viết một trình biên dịch trong tương lai gần; Tuy nhiên, tôi khá hứng thú với các công nghệ biên dịch và làm thế nào công cụ này có thể được làm tốt hơn.

Bắt đầu với các ngôn ngữ được biên dịch, hầu hết các trình biên dịch có hai mức lỗi: cảnh báo và lỗi, đầu tiên là phần lớn thời gian không gây tử vong mà bạn nên sửa và các lỗi cho thấy hầu hết thời gian không thể tạo ra máy- (hoặc byte-) mã từ đầu vào.

Mặc dù, đây là một định nghĩa khá yếu. Trong một số ngôn ngữ như Java, một số cảnh báo đơn giản là không thể thoát khỏi mà không sử dụng lệnh @SuppressWarningnày. Ngoài ra, Java coi các vấn đề không nghiêm trọng nhất định là lỗi (ví dụ: mã không thể truy cập được trong Java gây ra lỗi vì một lý do tôi muốn biết).

C # không có cùng một vấn đề, nhưng nó có một vài vấn đề. Có vẻ như quá trình biên dịch xảy ra trong một số lần vượt qua và việc vượt qua thất bại sẽ khiến các đường chuyền tiếp theo không được thực thi. Do đó, số lỗi bạn nhận được khi bản dựng của bạn thất bại thường bị đánh giá thấp. Trong một lần chạy, nó có thể cho biết bạn có hai lỗi, nhưng một khi bạn sửa chúng, có thể bạn sẽ gặp 26 lỗi mới.

Việc đào sâu vào C và C ++ chỉ đơn giản cho thấy sự kết hợp tồi tệ trên các điểm yếu chẩn đoán biên dịch của Java và C # (mặc dù có thể chính xác hơn khi nói rằng Java và C # chỉ đi theo một nửa vấn đề). Một số cảnh báo thực sự phải là lỗi (ví dụ: khi không phải tất cả các đường dẫn mã đều trả về giá trị) và vẫn là cảnh báo bởi vì, tôi cho rằng, tại thời điểm họ viết tiêu chuẩn, công nghệ trình biên dịch không đủ tốt để tạo ra các loại này kiểm tra bắt buộc. Trong cùng một hướng, trình biên dịch thường kiểm tra nhiều hơn so với tiêu chuẩn nói, nhưng vẫn sử dụng mức lỗi cảnh báo "tiêu chuẩn" cho các phát hiện bổ sung. Và thông thường, trình biên dịch sẽ không báo cáo tất cả các lỗi mà họ có thể tìm thấy ngay lập tức; nó có thể mất một vài biên dịch để loại bỏ tất cả chúng. Chưa kể các lỗi khó hiểu về trình biên dịch C ++ muốn nhổ,

Bây giờ thêm rằng nhiều hệ thống xây dựng có thể cấu hình để báo cáo lỗi khi trình biên dịch phát ra cảnh báo, chúng tôi chỉ nhận được một hỗn hợp lạ: không phải tất cả các lỗi đều gây tử vong nhưng một số cảnh báo nên; không phải tất cả các cảnh báo đều xứng đáng nhưng một số được loại bỏ rõ ràng mà không đề cập thêm về sự tồn tại của chúng; và đôi khi tất cả các cảnh báo trở thành lỗi.

Các ngôn ngữ không được biên dịch vẫn có phần báo cáo lỗi nhảm nhí. Typose trong Python sẽ không được báo cáo cho đến khi mã thực sự được chạy và bạn không bao giờ có thể thực sự mắc nhiều lỗi một lần vì tập lệnh sẽ ngừng thực thi sau khi gặp mã.

PHP, về phía nó, có một loạt các mức độ lỗi ít nhiều đáng kể và các ngoại lệ. Các lỗi phân tích được báo cáo cùng một lúc, các cảnh báo thường rất tệ, họ nên hủy bỏ tập lệnh của bạn (nhưng không mặc định), các thông báo thực sự thường hiển thị các vấn đề logic nghiêm trọng, một số lỗi thực sự không đủ tệ để dừng tập lệnh của bạn nhưng vẫn và, như thường lệ với PHP, có một số điều thực sự kỳ lạ ở đó (tại sao chúng ta cần một mức độ lỗi cho các lỗi nghiêm trọng không thực sự gây tử vong?, E_RECOVERABLE_E_ERRORtôi đang nói chuyện với bạn).

Dường như với tôi rằng mỗi lần thực hiện báo cáo lỗi trình biên dịch tôi có thể nghĩ là bị hỏng. Đó là một sự xấu hổ thực sự, vì làm thế nào tất cả các lập trình viên giỏi nhấn mạnh vào tầm quan trọng của việc xử lý lỗi một cách chính xác và chưa thể có các công cụ của riêng họ để làm như vậy.

Bạn nghĩ gì nên là cách đúng để báo cáo lỗi trình biên dịch?


-1: "Các ngôn ngữ không được biên dịch vẫn có phần báo cáo lỗi nhảm nhí" Chủ quan và lập luận. Thực sự không có ích. Đây là một câu hỏi hoặc một khiếu nại?
S.Lott

2
@ S.Lott Tôi nghĩ rằng bạn đang có một chút ở rìa ở đây. Tôi thấy tôi đã khó khăn hơn nhiều đối với các ngôn ngữ được biên dịch và dường như điều đó không làm phiền bạn.
zneak

@zneak: Các câu khác gần với thực tế và khó phân tích hơn. Câu nói đó dễ dàng được thể hiện là chủ quan và lập luận.
S.Lott

1
@ S.Lott Tôi có nói sai rằng Python chỉ ra một lỗi tại một thời điểm không?
zneak

1
@ S.Lott Sau đó, mọi thứ đã thay đổi, vì lần trước tôi đã thử, bất kỳ lỗi cú pháp nào cũng sẽ khiến Python ngừng cố gắng "biên dịch" và một lỗi tên sẽ ném ngoại lệ và không kiểm tra phần còn lại của hàm (mặc dù điều này đã bỏ đi phòng để báo cáo một lỗi cho mỗi đơn vị kiểm tra). Tuyên bố chủ quan và lập luận của tôi là một giới thiệu về những gì tôi tin là sự thật, nhưng nếu nó không còn đúng nữa tôi sẽ đi và chỉnh sửa câu hỏi của mình. Làm thế nào nó hoạt động bây giờ?
zneak

Câu trả lời:


6

Câu hỏi của bạn dường như không thực sự là về cách chúng tôi báo cáo lỗi trình biên dịch - thay vào đó, đó là về việc phân loại các vấn đề và phải làm gì với chúng.

Nếu chúng ta bắt đầu bằng cách giả sử, hiện tại, rằng sự phân đôi cảnh báo / lỗi là chính xác, hãy xem chúng ta có thể xây dựng tốt như thế nào trên đó. Một vài ý tưởng:

  1. "Cấp độ" cảnh báo khác nhau. Rất nhiều trình biên dịch thực hiện việc này (ví dụ GCC có rất nhiều công tắc để định cấu hình chính xác những gì nó sẽ cảnh báo), nhưng nó cần hoạt động - ví dụ, báo cáo mức độ nghiêm trọng của cảnh báo được báo cáo và khả năng đặt "cảnh báo là các lỗi "chỉ cho các cảnh báo trên mức độ nghiêm trọng đã chỉ định.

  2. Sane phân loại lỗi và cảnh báo. Một lỗi chỉ nên được báo cáo nếu mã không đáp ứng đặc điểm kỹ thuật và do đó không thể được biên dịch. Các câu lệnh không thể truy cập, trong khi có lẽ là lỗi mã hóa, phải là một cảnh báo , không phải là lỗi - mã vẫn "hợp lệ" và có những trường hợp hợp pháp trong đó người ta muốn biên dịch với mã không thể truy cập (ví dụ sửa đổi nhanh để gỡ lỗi) .

Bây giờ những điều tôi không đồng ý với bạn về:

  1. Nỗ lực thêm để báo cáo mọi vấn đề. Nếu có lỗi, điều đó phá vỡ bản dựng. Bản dựng bị hỏng. Bản dựng sẽ không hoạt động cho đến khi lỗi đó được sửa. Do đó, tốt hơn là báo cáo lỗi đó ngay lập tức, thay vì "tiếp tục" để thử và xác định mọi thứ khác "sai" với mã. Đặc biệt là khi rất nhiều những điều đó có thể được gây ra bởi lỗi ban đầu.

  2. Ví dụ cụ thể của bạn về một cảnh báo-đáng lẽ phải có lỗi. Vâng, nó có thể là một lỗi lập trình viên. Không, nó không nên phá vỡ bản dựng. Nếu tôi biết đầu vào của hàm sao cho nó sẽ luôn trả về một giá trị, tôi sẽ có thể chạy bản dựng và thực hiện một số thử nghiệm mà không phải thêm các kiểm tra bổ sung đó. Vâng, nó nên là một cảnh báo. Và một mức độ nghiêm trọng chết tiệt ở đó. Nhưng nó không nên phá vỡ bản dựng, trừ khi biên dịch với các cảnh báo là lỗi.

Suy nghĩ?


Tôi đồng ý với bạn, ngoại trừ những điểm chúng tôi không đồng ý (duh), vì vậy đó là +1 từ tôi. Tôi nghĩ rằng đủ dễ dàng để làm cho mọi đường dẫn mã trả về giá trị hoặc hủy bỏ chương trình của bạn, xem xét mức độ tồi tệ của nó khi bạn thực sự rơi vào trường hợp hành vi không xác định.
zneak

7

Một vấn đề bạn đưa ra là báo cáo lỗi không đầy đủ - ví dụ: báo cáo 2 lỗi và khi bạn sửa chúng, bạn sẽ nhận được nhiều hơn.

Đây là (phần lớn) một sự thỏa hiệp về phía người viết trình biên dịch. Tùy thuộc vào lỗi bạn đã gây ra, trình biên dịch rất dễ bắt đầu hiểu sai về những gì bạn làm đủ tệ đến mức nó bắt đầu báo cáo các lỗi rất ít liên quan đến thực tế. Ví dụ, hãy xem xét một lỗi đánh máy đơn giản, nơi bạn có một cái gì đó giống như itn x;thay vì int x;. Trừ khi bạn đã làm một cái gì đó itncó nghĩa là một cái gì đó, điều này sẽ được báo cáo là một lỗi. Điều đó tốt cho đến nay, nhưng bây giờ hãy xem xét những gì xảy ra tiếp theo - trình biên dịch xem xét rất nhiều mã cố gắng sử dụng x như một biến. Nó có nên dừng lại và để bạn sửa lỗi đó không, hoặc B) phát sinh 2000 lỗi về error: "x": undeclared identifierhoặc thứ gì đó theo thứ tự đó? Xem xét một khả năng khác:

int main()[

Đây là một lỗi đánh máy khá rõ ràng - rõ ràng nó nên là một {thay vì a [. Trình biên dịch có thể cho bạn biết phần đó khá dễ dàng - nhưng sau đó nó có nên báo cáo lỗi cho một cái gì đó như x=1;nói gì đó error: statement only allowed inside a functionkhông?

Lưu ý rằng đây thậm chí là những vấn đề khá nhỏ - những vấn đề tồi tệ hơn rất dễ tìm thấy (đặc biệt, như hầu hết chúng ta đều biết, khi bạn vào các mẫu C ++). Điểm mấu chốt là người viết trình biên dịch thường bị mắc kẹt với việc cố gắng thỏa hiệp giữa việc báo cáo lỗi sai (nghĩa là báo cáo một lỗi nào đó, mặc dù nó vẫn ổn) và không báo cáo lỗi thực sự. Có một số quy tắc của hầu hết tuân theo để cố gắng tránh đi quá xa theo cả hai hướng, nhưng hầu như không có cái nào trong số đó là gần hoàn hảo.

Một vấn đề khác mà bạn đề cập là Java và @SupressWarning. Điều này khá khác so với ở trên - nó sẽ khá tầm thường để sửa chữa. Lý do duy nhất không được khắc phục là vì làm như vậy không phù hợp với "đặc tính" cơ bản của Java - tức là, theo ý kiến ​​của họ, "đó không phải là một lỗi, đó là một tính năng." Mặc dù đó thường là một trò đùa, nhưng trong trường hợp này, những người liên quan đã sai lầm đến mức họ thực sự tin đó là sự thật.

Vấn đề bạn đề cập trong C và C ++ với các đường dẫn mã không trả về giá trị thực sự không cho phép các trình biên dịch nguyên thủy. Nó cho phép hàng thập kỷ hiện tại , một số trong đó không ai muốn sửa, chạm hoặc thậm chí đọc. Nó cổ kính và xấu xí nhưng nó hoạt động, và không ai muốn gì ngoài việc nó tiếp tục hoạt động. Dù tốt hay xấu, các ủy ban ngôn ngữ bị mắc kẹt khá nhiều với việc duy trì khả năng tương thích ngược, vì vậy họ tiếp tục cho phép những thứ mà không ai thực sự thích - nhưng một số người (ít nhất là nghĩ rằng họ) cần.


3
Ngoài quan điểm của bạn về các lỗi ban đầu gây ra cho nhiều người khác, còn có một thực tế là các đường chuyền sau thường được xây dựng để yêu cầu các đường chuyền trước đó phải hoàn thành thành công. Ví dụ: một trong những lần đầu tiên trong trình biên dịch C # kiểm tra để đảm bảo rằng không có chu kỳ nào trong biểu đồ thừa kế - bạn không có A thừa kế từ B kế thừa từ A. Nếu bạn muốn tiếp tục và tạo danh sách trong tất cả các lỗi sau đó, mỗi lần vượt qua sau đó sẽ phải có khả năng đối phó với các chu kỳ - làm cho nó chậm hơn đáng kể ngay cả trên các biên dịch "tốt".
Anon.

@Anon. Trình biên dịch Java thực hiện những nỗ lực tốt hơn nhiều trong việc sống sót qua những lần đầu tiên và tôi không thấy nó chậm hơn đáng kể. Đối với tôi nó hơi khó chịu khi nhanh chóng cscbỏ cuộc.
zneak

@zneak: Như Jerry nói, đó là một sự thỏa hiệp về phía các nhà phát triển trình biên dịch. Viết chẩn đoán lỗi tốt thực sự là một vấn đề rất khó khăn (hãy nhìn vào clang để biết ví dụ về việc bạn có thể thực sự đi được bao xa). Xem ở đây để thảo luận tốt về các giai đoạn và vượt qua của trình biên dịch C #.
Dean Harding
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.