Tại sao tôi phải luôn bật cảnh báo trình biên dịch?


302

Tôi thường nghe rằng khi biên dịch chương trình C và C ++, tôi nên "luôn luôn bật cảnh báo trình biên dịch". Tại sao điều này là cần thiết? Làm thế nào để làm điều đó?

Đôi khi tôi cũng nghe rằng tôi nên "coi cảnh báo là lỗi". Tôi có nên Làm thế nào để làm điều đó?

Câu trả lời:


341

Tại sao phải bật cảnh báo?

Trình biên dịch C và C ++ nổi tiếng là xấu khi báo cáo một số lỗi lập trình phổ biến theo mặc định , chẳng hạn như:

  • quên khởi tạo một biến
  • quên returnmột giá trị từ một hàm
  • đối số trong printfscanfgia đình không khớp với chuỗi định dạng
  • một chức năng được sử dụng mà không được khai báo trước (chỉ C)

Chúng có thể được phát hiện và báo cáo, thường không phải theo mặc định; tính năng này phải được yêu cầu rõ ràng thông qua các tùy chọn trình biên dịch.

Làm thế nào để kích hoạt cảnh báo?

Điều này phụ thuộc vào trình biên dịch của bạn.

Microsoft C và C ++ biên dịch hiểu công tắc thích /W1, /W2, /W3, /W4/Wall. Sử dụng ít nhất /W3. /W4/Wallcó thể phát ra các cảnh báo giả cho các tệp tiêu đề hệ thống, nhưng nếu dự án của bạn biên dịch rõ ràng với một trong các tùy chọn này, hãy thực hiện nó. Các tùy chọn này là loại trừ lẫn nhau.

Hầu hết các trình biên dịch khác hiểu các tùy chọn như -Wall, -Wpedantic-Wextra. -Walllà điều cần thiết và tất cả phần còn lại được khuyến nghị (lưu ý rằng, mặc dù tên của nó, -Wallchỉ cho phép các cảnh báo quan trọng nhất, không phải tất cả chúng). Các tùy chọn này có thể được sử dụng riêng biệt hoặc tất cả cùng nhau.

IDE của bạn có thể có cách kích hoạt những thứ này từ giao diện người dùng.

Tại sao coi cảnh báo là lỗi? Họ chỉ là những cảnh báo!

Một cảnh báo trình biên dịch báo hiệu một vấn đề nghiêm trọng tiềm ẩn trong mã của bạn. Các vấn đề được liệt kê ở trên hầu như luôn luôn gây tử vong; những người khác có thể hoặc không thể, nhưng bạn muốn biên dịch thất bại ngay cả khi nó trở thành một báo động sai. Điều tra từng cảnh báo, tìm nguyên nhân gốc và khắc phục nó. Trong trường hợp báo động sai, hãy xử lý xung quanh nó - nghĩa là sử dụng một tính năng ngôn ngữ khác hoặc xây dựng để cảnh báo không còn được kích hoạt. Nếu điều này chứng tỏ là rất khó, hãy vô hiệu hóa cảnh báo cụ thể đó trong từng trường hợp.

Bạn không muốn để lại cảnh báo là cảnh báo ngay cả khi tất cả chúng là báo động sai. Có thể ổn đối với các dự án rất nhỏ trong đó tổng số cảnh báo phát ra ít hơn 7. Bất cứ điều gì nhiều hơn và thật dễ dàng để một cảnh báo mới bị lạc trong một lũ lụt của những cái quen thuộc cũ. Đừng cho phép điều đó. Chỉ cần gây ra tất cả các dự án của bạn để biên dịch sạch sẽ.

Lưu ý điều này áp dụng cho phát triển chương trình. Nếu bạn đang phát hành dự án của mình ra thế giới ở dạng nguồn, thì có thể không nên cung cấp -Werrorhoặc tương đương trong tập lệnh xây dựng được phát hành của bạn . Mọi người có thể cố gắng xây dựng dự án của bạn với một phiên bản khác của trình biên dịch hoặc với một trình biên dịch khác hoàn toàn, có thể có một bộ cảnh báo khác được bật. Bạn có thể muốn xây dựng của họ để thành công. Vẫn là một ý tưởng tốt để giữ cho các cảnh báo được bật, để những người nhìn thấy thông báo cảnh báo có thể gửi cho bạn các báo cáo lỗi hoặc các bản vá.

Làm thế nào để coi cảnh báo là lỗi?

Điều này một lần nữa được thực hiện với các trình biên dịch chuyển đổi. /WXlà dành cho Microsoft, hầu hết những người khác sử dụng -Werror. Trong cả hai trường hợp, việc biên dịch sẽ thất bại nếu có bất kỳ cảnh báo nào được tạo ra.


107
Tôi đã đăng Câu hỏi này vì tôi phát ốm và mệt mỏi khi nói với mọi người để kích hoạt cảnh báo. Bây giờ tôi có thể chỉ họ ở đây (hoặc, nếu tôi đang ở trong một tâm trạng đặc biệt xấu xa, hãy đóng câu hỏi của họ dưới dạng lừa bịp). Bạn được chào đón để cải thiện câu trả lời này hoặc thêm của riêng bạn!
n. 'đại từ' m.

16
Bạn cũng có thể sử dụng kêu vang của -Weverything
PMG

9
Công cụ sửa đổi duy nhất tôi muốn thêm là một số cảnh báo có thể không hữu ích cho ứng dụng của bạn. (Tôi đã thấy cảnh báo rằng trình biên dịch đã thêm 2 byte đệm giữa các thành phần trong cấu trúc. Ứng dụng này dành cho tạo mẫu, do đó, một ít bộ nhớ bị lãng phí đã không làm phiền chúng tôi.) Hãy coi tất cả các cảnh báo là lỗi và sau đó chỉ vô hiệu hóa cảnh báo nếu bạn biết tại sao cảnh báo đó sẽ không giúp bạn.
Kyle A

20
Nhược điểm của việc coi các cảnh báo là lỗi đối với những người làm theo hướng dẫn xây dựng mặc định của bạn là mã của bạn bị lỗi khi trình biên dịch thêm cảnh báo mới. Người dùng tải xuống mã của bạn và cố gắng xây dựng mã trong tương lai có thể không thể, vì trình biên dịch của họ quá mới và đưa ra cảnh báo về một số dấu ngoặc đơn hoặc điều gì đó mà trình biên dịch của bạn không quan tâm. Người dùng gặp lỗi không chịu trách nhiệm về mã hoặc hệ thống xây dựng của bạn và không biết làm cách nào để tắt cảnh báo là lỗi và thực sự xây dựng dự án của bạn.
xen vào

15
@ interinf Có, điều này đã xảy ra với tôi một vài lần. Không có vấn đề gì Nếu bạn đã chọn để xây dựng một unmaintained phần của phần mềm sử dụng một trình biên dịch nó không bao giờ được thử nghiệm với, tốt, bạn tốt hơn được chuẩn bị để làm một số mainenance mình.
n. 'đại từ' m.

94

C, nổi tiếng, là một ngôn ngữ cấp thấp như HLL đi. C ++, mặc dù nó có vẻ là ngôn ngữ cấp cao hơn đáng kể so với C, nhưng vẫn có chung một số đặc điểm của nó. Và một trong những đặc điểm đó là các ngôn ngữ được thiết kế bởi các lập trình viên, dành cho lập trình viên - và đặc biệt, các lập trình viên biết họ đang làm gì.

[Trong phần còn lại của câu trả lời này, tôi sẽ tập trung vào C. Hầu hết những gì tôi sẽ nói cũng áp dụng cho C ++, mặc dù có lẽ không mạnh bằng. Mặc dù như Bjarne Stroustrup đã nói một cách nổi tiếng, "C giúp bạn dễ dàng tự bắn vào chân mình; C ++ làm cho nó khó hơn, nhưng khi bạn làm điều đó sẽ thổi bay toàn bộ chân của bạn." ]

Nếu bạn biết những gì bạn đang làm - thực sự biết những gì bạn đang làm - đôi khi bạn có thể phải "phá vỡ các quy tắc". Nhưng hầu hết thời gian, hầu hết chúng ta sẽ đồng ý rằng các quy tắc có thiện chí sẽ giữ cho chúng ta thoát khỏi rắc rối, và việc cố tình phá vỡ các quy tắc đó mọi lúc là một ý tưởng tồi.

Nhưng trong C và C ++, có một số lượng lớn đáng ngạc nhiên những điều bạn có thể làm đó là "ý tưởng tồi" nhưng không chính thức "chống lại các quy tắc". Đôi khi chúng là một ý tưởng tồi trong một số thời điểm (nhưng có thể được bảo vệ vào những thời điểm khác); đôi khi chúng là một ý tưởng tồi hầu như mọi lúc. Nhưng truyền thống luôn không cảnh báo về những điều này - bởi vì, một lần nữa, giả định là các lập trình viên biết họ đang làm gì, họ sẽ không làm những việc này mà không có lý do chính đáng, họ sẽ bị làm phiền bởi một đám cảnh báo không cần thiết.

Nhưng tất nhiên không phải tất cả các lập trình viên thực sự biết họ đang làm gì. Và đặc biệt, mọi lập trình viên C (dù có kinh nghiệm đến đâu) đều trải qua giai đoạn trở thành lập trình viên C khởi đầu. Và ngay cả các lập trình viên C có kinh nghiệm cũng có thể bất cẩn và mắc lỗi.

Cuối cùng, kinh nghiệm đã chỉ ra rằng không chỉ các lập trình viên mắc lỗi, mà những sai lầm này có thể gây ra hậu quả nghiêm trọng thực sự. Nếu bạn mắc lỗi và trình biên dịch không cảnh báo bạn về điều đó, và bằng cách nào đó, chương trình không ngay lập tức bị lỗi hoặc làm gì đó rõ ràng là sai vì nó, lỗi có thể ẩn ở đó, đôi khi trong nhiều năm, cho đến khi nó gây ra một vấn đề thực sự lớn

Vì vậy, hóa ra, hầu hết thời gian, cảnh báo là một ý tưởng tốt, sau tất cả. Ngay cả các lập trình viên có kinh nghiệm cũng đã học (thực ra, đó là " đặc biệt là các lập trình viên có kinh nghiệm đã học") rằng, trên sự cân bằng, các cảnh báo có xu hướng làm tốt hơn hại. Mỗi lần bạn làm điều gì đó sai một cách có chủ ý và cảnh báo là một sự phiền toái, có lẽ ít nhất mười lần bạn đã làm sai điều gì đó do tai nạn và cảnh báo đã cứu bạn khỏi những rắc rối tiếp theo. Và hầu hết các cảnh báo có thể bị vô hiệu hóa hoặc hoạt động trong vài lần khi bạn thực sự muốn làm điều "sai".

(Một ví dụ điển hình của việc như một "sai lầm" là thử nghiệm if(a = b)Hầu hết thời gian, đây là một sai lầm, vì vậy hầu hết các trình biên dịch những ngày này cảnh báo về nó -.. Một số thậm chí theo mặc định Nhưng nếu bạn thực sự muốn cả assign bđể avà thử nghiệm kết quả, bạn có thể tắt cảnh báo bằng cách nhập if((a = b)).)

Câu hỏi thứ hai là, tại sao bạn muốn yêu cầu trình biên dịch coi các cảnh báo là lỗi? Tôi muốn nói rằng đó là vì bản chất con người, cụ thể là phản ứng quá dễ dàng khi nói "Ồ, đó chỉ là một cảnh báo, điều đó không quá quan trọng, tôi sẽ làm sạch nó sau." Nhưng nếu bạn là người trì hoãn (và tôi không biết về bạn, nhưng tôi là người trì hoãn khủng khiếp ) thì thật dễ dàng để dọn dẹp tất cả mọi thứ về cơ bản - và nếu bạn có thói quen bỏ qua các cảnh báo, thì đó là trở nên dễ dàng và dễ dàng hơn để bỏ lỡ một thông điệp cảnh báo quan trọng đang ngồi ở đó, không được chú ý, ở giữa tất cả những tin nhắn bạn đang bỏ qua.

Vì vậy, yêu cầu trình biên dịch coi các cảnh báo là lỗi là một mẹo nhỏ mà bạn có thể tự chơi để giải quyết vấn đề này.

Cá nhân, tôi không khăng khăng coi các cảnh báo là lỗi. (Trên thực tế, nếu tôi trung thực, tôi có thể nói rằng tôi hầu như không bao giờ kích hoạt tùy chọn đó trong lập trình "cá nhân" của mình.) Nhưng bạn có thể chắc chắn rằng tôi đã bật tùy chọn đó tại nơi làm việc, nơi hướng dẫn phong cách của chúng tôi (mà tôi đã viết) bắt buộc sử dụng nó. Và tôi sẽ nói - tôi nghi ngờ hầu hết các lập trình viên chuyên nghiệp sẽ nói - rằng bất kỳ cửa hàng nào không coi các cảnh báo là lỗi trong C đều hành xử thiếu trách nhiệm, không tuân thủ các thông lệ tốt nhất trong ngành được chấp nhận.


9
"Các lập trình viên biết họ đang làm gì" - LOL; có một ngụy biện "không có người Scotland thực sự" nếu tôi từng thấy nó :)
Dancrumb

3
@Dancrumb LOL trở lại atcha. Tôi không bao giờ chắc chắn tôi hiểu được ngụy biện Không có người Scotland thực sự, nhưng tôi thích nó, vì vậy đây sẽ là một bài tập tốt cho tôi. Tôi đoán ứng dụng ở đây giống như thế này: "Không lập trình viên C nào sẽ viết if(a = b), do đó chúng tôi không cần phải cảnh báo về nó." (Sau đó, một người nào đó tạo ra danh sách 10 lỗi nghiêm trọng trong 10 sản phẩm được phát hành do lỗi cụ thể này.) "Được rồi, không có lập trình viên C có kinh nghiệm nào sẽ viết điều đó ..."
Steve Summit

3
@SteveSummit nhưng một lập trình viên C thực sự có kinh nghiệm có thể viết if (returnCodeFromFoo = foo(bar))và có nghĩa là, để nắm bắt và kiểm tra mã ở một nơi (Giả sử mục đích duy nhấtfoo là có tác dụng phụ!) Thực tế là một lập trình viên thực sự có kinh nghiệm có thể biết đây không phải là một phong cách mã hóa tốt là bên cạnh điểm;)
alephzero

5
Điều này là, hầu hết các lập trình viên rất có kinh nghiệm cho phép hầu hết các cảnh báo, nếu không phải tất cả, cảnh báo. Nếu họ muốn sử dụng một cái gì đó như thế if (returnCodeFromFoo = foo(bar)), sau đó họ đưa ra một nhận xét và tắt cảnh báo (để khi lập trình viên bảo trì nhìn vào nó 4 năm sau, anh ấy / cô ấy sẽ nhận ra rằng mã là có chủ ý. với một người ở (trong vùng đất Microsoft C ++) đã khăng khăng rằng kết hợp / Tường với việc xử lý các cảnh báo là lỗi là điều nên làm. Uh, không phải vậy (trừ khi bạn muốn đưa ra nhiều bình luận đàn áp).
Flydog57

3
Là một người không viết mã hàng ngày, nhưng khi tôi làm nó có xu hướng là kim loại trần (thường trên một bảng thiết kế của riêng tôi) tôi thấy các cảnh báo là vô giá. Khi nhồi các giá trị vào các thanh ghi bên trong (đối với vị trí mô tả DMA là một ví dụ), cảnh báo về chuyển đổi thành con trỏ có nghĩa là tôi thực hiện một thao tác để xóa cảnh báo. Nó sẽ không phải là một lỗi, nhưng nếu ai đó (hoặc thậm chí là chính tôi!) Nhận mã đó trong một vài tháng thì nó cũng có thể gây nhầm lẫn. Ngoài ra, tôi cũng áp dụng quy tắc không có cảnh báo cho các đầu ra của các công cụ CAD của mình.
Peter Smith

39

Cảnh báo bao gồm những lời khuyên tốt nhất mà một số nhà phát triển C ++ lành nghề nhất có thể đưa vào một ứng dụng. Chúng đáng để giữ xung quanh.

C ++, là một ngôn ngữ hoàn chỉnh Turing, có rất nhiều trường hợp trong đó trình biên dịch phải đơn giản tin tưởng rằng bạn biết bạn đang làm gì. Tuy nhiên, có nhiều trường hợp trình biên dịch có thể nhận ra rằng bạn có thể không có ý định viết những gì bạn đã viết. Một ví dụ kinh điển là các mã printf () không khớp với các đối số hoặc chuỗi std :: được truyền cho printf (không phải điều đó từng xảy ra với tôi!). Trong những trường hợp này, mã bạn đã viết không phải là một lỗi. Đó là một biểu thức C ++ hợp lệ với một diễn giải hợp lệ để trình biên dịch hành động. Nhưng trình biên dịch có một linh cảm mạnh mẽ mà bạn chỉ cần bỏ qua thứ gì đó dễ dàng cho trình biên dịch hiện đại phát hiện ra. Đây là những cảnh báo. Chúng là những thứ hiển nhiên đối với trình biên dịch, sử dụng tất cả các quy tắc nghiêm ngặt của C ++ theo ý của nó, mà bạn có thể đã bỏ qua.

Tắt cảnh báo, hoặc bỏ qua chúng, giống như chọn bỏ qua lời khuyên miễn phí từ những người có kỹ năng hơn bạn. Đó là một bài học về huberis kết thúc khi bạn bay quá gần mặt trời và đôi cánh của bạn tan chảy, hoặc xảy ra lỗi hỏng bộ nhớ. Giữa hai người, tôi sẽ rơi từ trên trời xuống bất cứ ngày nào!

"Coi cảnh báo là lỗi" là phiên bản cực đoan của triết lý này. Ý tưởng ở đây là bạn giải quyết mọi cảnh báo mà trình biên dịch đưa ra cho bạn - bạn lắng nghe từng lời khuyên miễn phí và hành động theo nó. Đây có phải là một mô hình tốt để phát triển cho bạn hay không phụ thuộc vào nhóm và loại sản phẩm bạn đang làm việc. Đó là cách tiếp cận khổ hạnh mà một nhà sư có thể có. Đối với một số người, nó hoạt động tuyệt vời. Đối với những người khác, nó không.

Trên nhiều ứng dụng của tôi, chúng tôi không coi các cảnh báo là lỗi. Chúng tôi làm điều này bởi vì các ứng dụng cụ thể này cần phải biên dịch trên một số nền tảng với một số trình biên dịch ở các độ tuổi khác nhau. Đôi khi chúng tôi thấy thực sự không thể sửa cảnh báo ở một bên mà không biến nó thành cảnh báo trên nền tảng khác. Vì vậy, chúng tôi chỉ đơn giản là cẩn thận. Chúng tôi tôn trọng các cảnh báo, nhưng chúng tôi không cúi xuống về phía sau cho họ.


11
C ++ đã hoàn thành Turing phải làm gì với điều đó. Rất nhiều ngôn ngữ đang hoàn tất và không tin tưởng bạn nếu bạn làm sai ....
Tạm biệt SE

3
@KamiKaze mọi ngôn ngữ sẽ có những lỗi thành ngữ (ví dụ: Java không thể ngăn bạn viết một từ không nhất quán equals/ hashCode) và đó là vấn đề chất lượng của việc thực thi được báo cáo.
Caleth

2
@KamiKaze Bit hoàn chỉnh Turing xuất hiện để chỉ ra rằng có những trường hợp trình biên dịch không thể chứng minh rằng mã của bạn sẽ không hoạt động như kế hoạch. Điều này rất quan trọng vì trình biên dịch không thể làm cho tất cả mã "sai" bị lỗi. Lỗi chỉ có thể được dành riêng cho các hành vi mà các nhà thiết kế ngôn ngữ chắc chắn sẽ luôn "sai". (thường là vì nó dẫn xuống các đường dẫn không nhất quán).
Cort Ammon

2
Điều này cũng chỉ ra thách thức với "tất cả các cảnh báo là lỗi." Các cảnh báo, theo thiết kế, mang tính cơ hội hơn, kích hoạt một số mã có khả năng đúng để đổi lấy việc kích hoạt mã sai thường xuyên hơn. Cảnh báo là lỗi dẫn đến bạn không thể thực hiện các khả năng của ngôn ngữ đầy đủ.
Cort Ammon

2
Tuy nhiên, nói chung, các lập trình viên muốn một ngôn ngữ không chỉ là một thứ "an toàn". Chúng tôi muốn một ngôn ngữ làm điều mà chúng tôi nghĩ rằng chúng tôi đã nói nó làm. Do đó, các cảnh báo vẫn quan trọng vì lớp thực tế của những thứ chúng ta muốn máy tính làm là một lớp ngữ nghĩa. Trình biên dịch có thể loại bỏ nó bằng cách định nghĩa "không chính xác" hoặc "không an toàn", nhưng cuối cùng bạn vẫn có một siêu lớp các hành vi mà lập trình viên muốn chương trình thực hiện. Cảnh báo giúp thu hẹp siêu lớp đó xuống.
Cort Ammon

19

Không chỉ xử lý các cảnh báo làm cho mã tốt hơn, nó làm cho bạn trở thành một lập trình viên tốt hơn. Cảnh báo sẽ cho bạn biết về những điều có vẻ ít đối với bạn ngày hôm nay, nhưng một ngày nào đó thói quen xấu đó sẽ quay trở lại và cắn đầu bạn.

Sử dụng đúng loại, trả về giá trị đó, đánh giá giá trị trả về đó. Hãy dành thời gian và suy ngẫm "Đây có thực sự là loại chính xác trong bối cảnh này?" "Tôi có cần trả lại cái này không?" Và ông lớn; "Mã này sẽ có thể di động trong 10 năm tới?"

Tập thói quen viết mã cảnh báo miễn phí ngay từ đầu.


17

Các câu trả lời khác là tuyệt vời và tôi không muốn lặp lại những gì họ đã nói.

Một khía cạnh khác của "tại sao cho phép cảnh báo" chưa được chạm đúng là chúng giúp ích rất nhiều cho việc bảo trì mã. Khi bạn viết một chương trình có kích thước đáng kể, sẽ không thể giữ toàn bộ mọi thứ trong đầu bạn cùng một lúc. Bạn thường có một hoặc ba chức năng mà bạn chủ động viết và suy nghĩ, và có lẽ một hoặc ba tệp trên màn hình của bạn mà bạn có thể tham khảo, nhưng phần lớn chương trình tồn tại trong nền ở đâu đó và bạn phải tin rằng nó tiếp tục làm việc

Có cảnh báo và để chúng tràn đầy năng lượng và vào mặt bạn nhất có thể, giúp cảnh báo bạn nếu có gì đó bạn thay đổi gây rắc rối cho thứ gì đó mà bạn không thể nhìn thấy.

Lấy ví dụ, cảnh báo tiếng kêu -Wswitch-enum. Điều đó kích hoạt cảnh báo nếu bạn sử dụng công tắc trên enum và bỏ lỡ một trong những giá trị enum có thể. Đó là điều mà bạn có thể nghĩ sẽ là một sai lầm không thể xảy ra: ít nhất bạn có thể đã xem danh sách các giá trị enum khi bạn viết câu lệnh chuyển đổi. Bạn thậm chí có thể có một IDE tạo ra các tùy chọn chuyển đổi cho bạn, không có chỗ cho lỗi của con người.

Cảnh báo này thực sự xuất hiện khi sáu tháng sau bạn thêm một mục có thể vào enum. Một lần nữa, nếu bạn đang nghĩ về mã trong câu hỏi có lẽ bạn sẽ ổn. Nhưng nếu enum này được sử dụng cho nhiều mục đích khác nhau và nó là một trong những mục đích bạn cần tùy chọn bổ sung, thì rất dễ quên cập nhật một công tắc trong tệp bạn đã chạm trong 6 tháng.

Bạn có thể nghĩ về các cảnh báo giống như cách bạn nghĩ về các trường hợp kiểm thử tự động: chúng giúp bạn đảm bảo rằng mã đó hợp lý và làm những gì bạn cần khi bạn viết nó lần đầu tiên, nhưng chúng thậm chí còn giúp nhiều hơn để đảm bảo rằng nó tiếp tục làm những gì bạn cần trong khi bạn ủng hộ nó. Sự khác biệt là các trường hợp thử nghiệm hoạt động rất hẹp với các yêu cầu của mã của bạn và bạn phải viết chúng, trong khi các cảnh báo hoạt động rộng rãi theo các tiêu chuẩn hợp lý cho hầu hết tất cả các mã, và chúng được cung cấp rất rộng rãi bởi các boffin tạo ra các trình biên dịch.


9
Một cách khác mà họ giúp bảo trì là khi bạn đang xem mã của người khác và không thể biết liệu tác dụng phụ có phải là cố ý hay không. Với các cảnh báo trên, bạn biết rằng ít nhất họ đã nhận thức được vấn đề.
Robin Bennett

Hoặc trong trường hợp của tôi, bạn nhập một tệp từ một hệ thống nhúng có chứa hơn 3000 câu lệnh chuyển đổi dòng trên một enum với vài nghìn giá trị. Các cảnh báo "rơi qua" (tránh bằng cách sử dụng goto) che giấu một số lỗi "không được xử lý" ... trình biên dịch nhúng không phát ra một trong hai lỗi đó, tuy nhiên các lỗi rất quan trọng.
Móż

15

Sớm không cố định cảnh báo sẽ sớm dẫn đến lỗi trong mã của bạn .


Ví dụ, gỡ lỗi một lỗi phân đoạn, yêu cầu lập trình viên theo dõi gốc (nguyên nhân) của lỗi, thường nằm ở vị trí trước trong mã của bạn so với dòng cuối cùng gây ra lỗi phân đoạn.

Điều rất điển hình là nguyên nhân là một dòng mà trình biên dịch đã đưa ra cảnh báo mà bạn đã bỏ qua và dòng gây ra lỗi phân đoạn là dòng cuối cùng đã gây ra lỗi.

Sửa lỗi cảnh báo dẫn đến khắc phục sự cố .. Một cổ điển!

Một minh họa về những điều trên .. Hãy xem xét đoạn mã sau:

#include <stdio.h>

int main(void) {
  char* str = "Hello world!";
  int idx;

  // Colossal amount of code here, irrelevant to 'idx'

  printf("%c\n", str[idx]);

  return 0;
}

mà khi được biên dịch với cờ "Wextra" được truyền cho GCC, sẽ cho:

main.c: In function 'main':
main.c:9:21: warning: 'idx' is used uninitialized in this function [-Wuninitialized]
    9 |   printf("%c\n", str[idx]);
      |                     ^

mà tôi có thể bỏ qua và thực thi mã bằng mọi cách .. Và sau đó tôi sẽ chứng kiến ​​một lỗi phân đoạn "lớn", như giáo sư epicurus IP của tôi thường nói:

Lỗi phân đoạn

Để gỡ lỗi này trong kịch bản thế giới thực, người ta sẽ bắt đầu từ dòng gây ra lỗi phân đoạn và cố gắng tìm ra nguyên nhân của nguyên nhân .. Họ sẽ phải tìm kiếm những gì đã xảy ra istrbên trong số tiền khổng lồ đó mã ở đằng kia ...

Cho đến một ngày, họ thấy mình trong tình huống phát hiện ra rằng nó idxđược sử dụng chưa được khởi tạo, do đó nó có giá trị rác, dẫn đến việc lập chỉ mục chuỗi (cách) vượt ra ngoài giới hạn của nó, dẫn đến lỗi phân đoạn.

Nếu chỉ họ không bỏ qua cảnh báo, họ sẽ tìm thấy lỗi ngay lập tức!


4
Để tiêu đề của bạn: không nhất thiết. Chẳng hạn, một cảnh báo đề xuất sử dụng dấu ngoặc đơn trong một công thức thực sự không cần chúng chỉ ra một vấn đề không bao giờ gây ra lỗi. Các ưu tiên toán tử trong một ngôn ngữ lập trình nhất định không thay đổi. Không bao giờ.
Marc van Leeuwen

4
@MarcvanLeeuwen Ví dụ bạn trích dẫn có thể biến thành lỗi tho, ví dụ nếu lập trình viên không nhớ toán tử ưu tiên sửa đổi chính xác công thức một chút. Cảnh báo cho bạn biết: "đôi khi có thể không rõ ràng với ai đó, hãy thêm một số dấu ngoặc đơn để làm cho nó rõ ràng hơn". Mặc dù người ta phải đồng ý rằng tiêu đề của bài viết gốc không phải lúc nào cũng đúng.
Hubert Jasieniecki

^ Bất cứ điều gì có thể được biến thành một lỗi. Thật dễ dàng để giới thiệu một lỗi vào mã được ngoặc đơn một phần như vào mã được ngoặc đơn hoàn toàn.
Jim Balter

... Ở một bên, tôi có câu hỏi cho trình gỡ lỗi có phản ứng đầu tiên với "Ồ, nó bị tách ra khỏi str[idx]" không phải là "Được rồi, ở đâu stridxđược xác định?"
Justin Time - Tái lập Monica

2
Bạn thật may mắn nếu bạn gặp phải một lỗi phân khúc. Nếu bạn kém may mắn hơn, bạn có thể tình cờ idxtrở thành giá trị bạn mong đợi trong bài kiểm tra của mình (không quá khó xảy ra nếu giá trị mong đợi là 0) và thực sự chỉ ra một số dữ liệu nhạy cảm không bao giờ được in khi triển khai.
celtschk

14

Xử lý các cảnh báo là lỗi chỉ là một biện pháp tự kỷ luật: bạn đã biên dịch một chương trình để kiểm tra tính năng mới sáng bóng đó, nhưng bạn không thể cho đến khi bạn sửa các phần cẩu thả. Không có thông tin bổ sung Werrorcung cấp, nó chỉ đặt ưu tiên rất rõ ràng:

Không thêm mã mới cho đến khi bạn khắc phục sự cố trong mã hiện có

Đó thực sự là suy nghĩ quan trọng, không phải là công cụ. Trình biên dịch chẩn đoán đầu ra là một công cụ. MISRA (cho C nhúng) là một công cụ khác. Không quan trọng bạn sử dụng cái nào, nhưng có thể cảnh báo trình biên dịch là công cụ đơn giản nhất bạn có thể nhận được (chỉ cần một cờ để đặt) và tỷ lệ tín hiệu trên nhiễu rất cao. Vì vậy, không có lý do gì không để sử dụng nó.

Không có công cụ là không thể sai lầm. Nếu bạn viết const float pi = 3.14;, hầu hết các công cụ sẽ không cho bạn biết rằng bạn đã xác định π với độ chính xác kém có thể dẫn đến các sự cố. Hầu hết các công cụ sẽ không nhướn mày if(tmp < 42), ngay cả khi người ta thường biết rằng việc đưa ra các biến vô nghĩa và sử dụng số ma thuật là một cách để gây ra thảm họa trong các dự án lớn. Bạn phải hiểu rằng bất kỳ mã "kiểm tra nhanh" nào bạn viết chỉ là: một bài kiểm tra và bạn phải lấy nó ngay trước khi bạn chuyển sang các nhiệm vụ khác, trong khi bạn vẫn thấy những thiếu sót của nó. Nếu bạn để nguyên mã đó, việc gỡ lỗi nếu sau khi bạn dành hai tháng để thêm các tính năng mới sẽ khó hơn đáng kể.

Một khi bạn có được suy nghĩ đúng đắn, không có điểm nào trong việc sử dụng Werror. Có các cảnh báo là cảnh báo sẽ cho phép bạn đưa ra quyết định sáng suốt cho dù việc chạy phiên gỡ lỗi mà bạn chuẩn bị bắt đầu hay hủy bỏ và sửa các cảnh báo trước là điều hợp lý.


3
Dù tốt hơn hay tồi tệ hơn, clippycông cụ linting cho Rust thực sự sẽ cảnh báo về hằng số "3.14". Đó thực sự là một ví dụ trong các tài liệu . Nhưng như bạn có thể đoán từ cái tên, clippytự hào về sự tích cực hữu ích.
emk

1
@emk Cảm ơn ví dụ này, có lẽ tôi nên viết lại câu trả lời của mình theo cách không bao giờ nói "không bao giờ" . Tôi không có ý nói rằng việc kiểm tra các giá trị π không chính xác là không thể, chỉ là việc loại bỏ các cảnh báo không đảm bảo chất lượng mã tốt.
Dmitry Grigoryev

Một điều cảnh báo là lỗi mang lại cho bạn là các bản dựng tự động sẽ thất bại, do đó cảnh báo cho bạn rằng đã xảy ra lỗi. Bản dựng tự động cũng cho phép tự động hóa linting (vụ nổ là 3 ... 2 ... 1 .. :)
Móż

8

Là một người làm việc với mã C nhúng kế thừa, việc bật cảnh báo trình biên dịch đã giúp hiển thị rất nhiều điểm yếu và các khu vực cần điều tra khi đề xuất sửa lỗi. Trong gcc sử dụng -Wall-Wextravà thậm chí-Wshadow đã trở nên quan trọng. Tôi sẽ không đi đến mọi nguy hiểm, nhưng tôi sẽ liệt kê một vài thứ đã xuất hiện giúp hiển thị các vấn đề về mã.

Các biến bị bỏ lại phía sau

Điều này có thể dễ dàng chỉ ra các công việc còn dang dở và các khu vực có thể không sử dụng tất cả các biến đã qua có thể là một vấn đề. Hãy xem xét một chức năng đơn giản có thể kích hoạt điều này:

int foo(int a, int b)
{
   int c = 0;

   if (a > 0)
   {
        return a;
   }
   return 0;
}

Chỉ cần biên dịch cái này mà không -Wall hoặc -Wextra trả về không có vấn đề. -Wall sẽ cho bạn biết mặc dù điều đó ckhông bao giờ được sử dụng:

foo.c: Trong chức năng 'foo':

foo.c: 9: 20: cảnh báo: biến không sử dụng 'c' [-Wunuse-biến]

-Wextra cũng sẽ cho bạn biết rằng tham số b của bạn không làm gì cả:

foo.c: Trong chức năng 'foo':

foo.c: 9: 20: cảnh báo: biến không sử dụng 'c' [-Wunuse-biến]

foo.c: 7: 20: cảnh báo: tham số không sử dụng 'b' [-Wunuse-tham số] int foo (int a, int b)

Biến bóng toàn cầu

Điều này một chút khó khăn và không hiển thị cho đến khi -Wshadowđược sử dụng. Chúng ta hãy sửa đổi ví dụ trên để chỉ thêm, nhưng tình cờ có một tên toàn cầu có cùng tên với một địa phương gây ra nhiều nhầm lẫn khi cố gắng sử dụng cả hai.

int c = 7;

int foo(int a, int b)
{
   int c = a + b;
   return c;
}

Khi -Wshadow được bật, thật dễ dàng để phát hiện vấn đề này.

foo.c: 11: 9: cảnh báo: khai báo 'c' đổ bóng một tuyên bố toàn cầu [-Wshadow]

foo.c: 1: 5: lưu ý: khai báo bị bóng ở đây

Định dạng chuỗi

Điều này không yêu cầu bất kỳ cờ bổ sung nào trong gcc, nhưng nó vẫn là nguồn gốc của các vấn đề trong quá khứ. Một chức năng đơn giản đang cố in dữ liệu, nhưng có lỗi định dạng có thể trông như thế này:

void foo(const char * str)
{
    printf("str = %d\n", str);
}

Điều này không in chuỗi vì cờ định dạng sai và gcc sẽ vui vẻ cho bạn biết đây có thể không phải là điều bạn muốn:

foo.c: Trong chức năng 'foo':

foo.c: 10: 12: warning: format '% d' mong đợi đối số của loại 'int', nhưng đối số 2 có loại 'const char *' [-Wformat =]


Đây chỉ là ba trong số nhiều thứ mà trình biên dịch có thể kiểm tra lại cho bạn. Có rất nhiều người khác thích sử dụng một biến chưa được khởi tạo mà những người khác đã chỉ ra.


7
Trong thế giới nhúng, các cảnh báo khiến tôi lo lắng nhất là các cảnh báo " possible loss of precision" và " comparison between signed and unsigned". Tôi cảm thấy khó khăn để nắm bắt có bao nhiêu "lập trình viên" bỏ qua những điều này (thực tế, tôi không thực sự chắc chắn tại sao họ không mắc lỗi)
Mawg nói rằng phục hồi Monica

3
Trong trường hợp sau, @Mawg, tôi tin rằng lý do chính không phải là lỗi là do kết quả của sizeofkhông dấu, nhưng loại số nguyên mặc định được ký. Các sizeofloại quả, size_t, thường được sử dụng cho bất cứ điều gì liên quan đến loại kích cỡ, chẳng hạn như, ví dụ, liên kết hoặc mảng / đếm yếu tố container, trong khi số nguyên nói chung được dự định sẽ được sử dụng như " inttrừ trường hợp cần thiết". Xem xét có bao nhiêu người được dạy sử dụng intđể lặp lại các thùng chứa của họ (so intvới size_t), làm cho nó trở thành một lỗi sẽ phá vỡ mọi thứ. ; P
Thời gian Justin - Phục hồi Monica

6

Đây là một câu trả lời cụ thể cho C và tại sao điều này lại quan trọng với C hơn bất kỳ điều gì khác.

#include <stdio.h>
int main()
{
   FILE *fp = "some string";
}

Mã này biên dịch với một cảnh báo . Những gì đang và nên là lỗi trong mọi ngôn ngữ khác trên hành tinh (ngôn ngữ lắp ráp chặn) là những cảnh báo trong C. Cảnh báo trong C hầu như luôn luôn là những lỗi được ngụy trang. Cảnh báo nên được sửa chữa, không bị đàn áp.

Với gcc, chúng tôi làm điều này như gcc -Wall -Werror.

Đây cũng là lý do cho sự phẫn nộ cao về một số cảnh báo API không an toàn của MS. Hầu hết mọi người lập trình C đã học được cách khó khăn để coi các cảnh báo là lỗi và công cụ này dường như không phải là loại tương tự và muốn sửa lỗi không di động.


5

CẢNH BÁO MÁY TÍNH LÀ BẠN B (CỦA BẠN (không la hét, viết hoa để nhấn mạnh).

Tôi làm việc trên các hệ thống Fortran-77 cũ. Trình biên dịch cho tôi biết những điều có giá trị: kiểu dữ liệu đối số không khớp trong lệnh gọi chương trình con, sử dụng biến cục bộ trước khi giá trị được đặt thành biến, nếu tôi có đối số biến hoặc chương trình con không được sử dụng. Đây là hầu như luôn luôn lỗi.

Tránh một bài viết dài: Khi mã của tôi biên dịch sạch, 97% nó hoạt động. Một anh chàng khác tôi làm việc với các trình biên dịch với tất cả các cảnh báo tắt, dành hàng giờ hoặc nhiều ngày trong trình gỡ lỗi, sau đó nhờ tôi giúp đỡ. Tôi chỉ biên dịch mã của anh ấy với các cảnh báo trên và nói cho anh ấy biết phải sửa gì.


5

Bạn phải luôn luôn bật cảnh báo trình biên dịch vì trình biên dịch thường có thể cho bạn biết những gì sai với mã của bạn. Để làm điều này, bạn chuyển -Wall -Wextrađến trình biên dịch.

Bạn thường coi các cảnh báo là lỗi vì các cảnh báo thường biểu thị rằng có gì đó không đúng với mã của bạn. Tuy nhiên, thường rất dễ bỏ qua các lỗi này. Do đó, coi chúng là lỗi sẽ khiến quá trình xây dựng không thành công nên bạn không thể bỏ qua lỗi. Để coi các cảnh báo là lỗi, chuyển -Werrorđến trình biên dịch.


4

Các cảnh báo trình biên dịch trong C ++ rất hữu ích vì một số lý do.

1 - Nó cho phép cho bạn thấy nơi bạn có thể đã phạm sai lầm, người có thể ảnh hưởng đến kết quả cuối cùng của hoạt động của bạn. Ví dụ: nếu bạn không khởi tạo một biến hoặc nếu bạn đặt "=" thay vì "==" (chỉ có ví dụ)

2 - Nó cũng cho phép bạn chỉ ra nơi mã của bạn không phù hợp với tiêu chuẩn của c ++. Nó hữu ích bởi vì nếu mã phù hợp với tiêu chuẩn thực tế, nó sẽ dễ dàng di chuyển mã sang một dạng tấm khác chẳng hạn.

Nói chung, các cảnh báo rất hữu ích để cho bạn biết nơi bạn có lỗi trong mã của mình, người có thể ảnh hưởng đến kết quả thuật toán của bạn hoặc ngăn ngừa một số lỗi khi người dùng sẽ sử dụng chương trình của bạn.


4

Bỏ qua các cảnh báo có nghĩa là bạn để lại mã cẩu thả không chỉ có thể gây ra vấn đề trong tương lai cho người khác mà còn khiến các tin nhắn biên dịch quan trọng ít được bạn chú ý. Càng nhiều trình biên dịch, càng ít người sẽ chú ý hoặc bận tâm. Càng sạch càng tốt. Nó cũng có nghĩa là bạn biết những gì bạn đang làm. Cảnh báo là rất không chuyên nghiệp, bất cẩn, và rủi ro.


4

Tôi đã từng làm việc cho một công ty lớn (Fortune 50) sản xuất thiết bị thử nghiệm điện tử.

Sản phẩm cốt lõi của nhóm tôi là một chương trình MFC, trong nhiều năm qua, đã tạo ra hàng trăm cảnh báo theo nghĩa đen. Mà đã bị bỏ qua trong hầu hết các trường hợp.

Đây là một cơn ác mộng đáng sợ khi lỗi xảy ra.

Sau vị trí đó, tôi đã may mắn được thuê làm nhà phát triển đầu tiên trong một công ty khởi nghiệp mới.

Tôi khuyến khích chính sách 'không cảnh báo' cho tất cả các bản dựng, với các mức cảnh báo của trình biên dịch được đặt là khá ồn.

Thực tiễn của chúng tôi là sử dụng cảnh báo #pragma - đẩy / vô hiệu hóa / pop cho mã mà nhà phát triển chắc chắn là thực sự tốt, cùng với một tuyên bố nhật ký ở cấp độ gỡ lỗi, chỉ trong trường hợp.

Thực hành này làm việc tốt cho chúng tôi.


1
Biệt phái. #pragma warningkhông chỉ ngăn chặn các cảnh báo, nó phục vụ mục đích kép là nhanh chóng thông báo cho các lập trình viên khác rằng một cái gì đó là cố ý và không vô tình, và hoạt động như một thẻ tìm kiếm để nhanh chóng xác định các khu vực có khả năng gặp sự cố khi sửa lỗi / cảnh báo sửa nó.
Thời gian của Justin - Phục hồi Monica

Bạn nói đúng Justin, đó chính xác là cách tôi đã xem cảnh báo #pragma
Jim In Texas

3

Một cảnh báo là một lỗi đang chờ để xảy ra. Vì vậy, bạn phải kích hoạt cảnh báo trình biên dịch và dọn dẹp mã của bạn để xóa bất kỳ cảnh báo nào.


3

Chỉ có một vấn đề với việc coi các cảnh báo là lỗi: Khi bạn sử dụng mã đến từ các nguồn khác (ví dụ: thư viện micro $ ** t, các dự án nguồn mở), họ đã không thực hiện đúng công việc của mình và biên dịch mã của họ tạo ra hàng tấn cảnh báo.

Tôi luôn viết mã của mình để nó không tạo ra bất kỳ cảnh báo hoặc lỗi nào và dọn sạch nó cho đến khi nó biên dịch mà không tạo ra bất kỳ tiếng ồn bên ngoài nào. Rác tôi phải làm việc với tôi, và tôi kinh ngạc khi tôi phải xây dựng một dự án lớn và xem một dòng cảnh báo đi qua nơi biên dịch chỉ nên thông báo những tập tin nào được xử lý.

Tôi cũng ghi lại mã của mình vì tôi biết chi phí thực sự của phần mềm chủ yếu đến từ bảo trì, không phải từ việc viết mã ban đầu, nhưng đó là một câu chuyện khác ...


Đừng đánh gục nó, có nhiều tiền trong công việc tư vấn cho những người có thể đọc to cảnh báo trình biên dịch cho khách hàng.
Móż

Mã từ các nguồn khác tạo ra cảnh báo không cần thiết có nghĩa là các tác giả đã cẩu thả. Điều đó cũng có nghĩa là họ đã biên dịch mã với một trình biên dịch khác nhau tạo ra một loạt các cảnh báo khác nhau. Mã có thể biên dịch mà không có cảnh báo trên một trình biên dịch và tạo cảnh báo trên một trình biên dịch khác. Hoặc có thể đó chỉ là một tập hợp các tùy chọn cảnh báo khác nhau; ví dụ như họ đã sử dụng -Wallvà bạn sử dụng -Wall -Wextra.
celtschk

2

Một số cảnh báo có thể có nghĩa là lỗi ngữ nghĩa có thể có trong mã hoặc có thể là UB. Ví dụ ;sau if(), biến không được sử dụng, biến toàn cục được che bởi cục bộ hoặc so sánh ký và không dấu. Nhiều cảnh báo có liên quan đến bộ phân tích mã tĩnh trong trình biên dịch hoặc vi phạm tiêu chuẩn ISO có thể phát hiện được tại thời điểm biên dịch, "yêu cầu chẩn đoán". Mặc dù những sự cố này có thể là hợp pháp trong một trường hợp cụ thể, nhưng chúng sẽ là kết quả của các vấn đề thiết kế hầu hết thời gian.

Một số trình biên dịch, ví dụ như gcc, có tùy chọn dòng lệnh để kích hoạt chế độ "cảnh báo là lỗi", đây là một công cụ tuyệt vời, nếu độc ác, để giáo dục các lập trình viên mới làm quen.


1

Việc trình biên dịch C ++ chấp nhận mã biên dịch rõ ràng dẫn đến hành vi không xác định hoàn toàn là một lỗ hổng lớn trong trình biên dịch. Lý do họ không khắc phục điều này là vì làm như vậy có thể sẽ phá vỡ một số bản dựng có thể sử dụng được.

Hầu hết các cảnh báo phải là lỗi nghiêm trọng ngăn cản việc xây dựng hoàn thành. Mặc định chỉ hiển thị lỗi và thực hiện quá trình xây dựng là sai và nếu bạn không ghi đè chúng để coi cảnh báo là lỗi và để lại một số cảnh báo thì có thể bạn sẽ bị chương trình của mình làm hỏng và làm những điều ngẫu nhiên.


Trớ trêu thay, rất nhiều hành vi không xác định thực sự không gây ra cảnh báo, nhưng âm thầm biên dịch tốt thành một quả bom thời gian nhỏ khó chịu. ; P
Thời gian Justin - Tái lập Monica

1
Vấn đề là nếu tiêu chuẩn yêu cầu thông báo lỗi, thông báo lỗi đó phải được ban hành trong mọi trường hợp xảy ra sự cố, nhưng không bao giờ nếu sự cố không xảy ra. Nhưng trong những trường hợp như hành vi không xác định, điều đó có thể không thể quyết định. Ví dụ, hãy xem xét đoạn mã sau: Mã int i; if (fun1()) i=2; if (fun2()) i=3; char s="abcde"[i];này thể hiện hành vi không xác định khi và chỉ khi cả hai fun1()fun2()có thể trả falsevề cùng một hàm thực thi. Điều này có thể đúng hoặc không đúng, nhưng trình biên dịch sẽ nói như thế nào?
celtschk

-2

Bạn chắc chắn nên kích hoạt cảnh báo trình biên dịch vì một số trình biên dịch không tốt trong việc báo cáo một số lỗi lập trình phổ biến, bao gồm các lỗi sau: -

-> khởi tạo một biến bị quên -> trả về một giá trị từ hàm bị bỏ qua -> các đối số đơn giản trong họ printf và scanf không khớp với chuỗi định dạng mà hàm được sử dụng mà không được khai báo trước, mặc dù chỉ xảy ra trong c

Vì vậy, vì các chức năng này có thể được phát hiện và báo cáo, thường không phải mặc định; vì vậy tính năng này phải được yêu cầu rõ ràng thông qua các tùy chọn trình biên dịch.


-32

Hãy dễ dàng: bạn không cần phải làm vậy, điều đó là không cần thiết. -Wall và -Werror được thiết kế bởi những kẻ điên tái cấu trúc mã cho chính : nó được phát triển bởi các nhà phát triển trình biên dịch để tránh phá vỡ các bản dựng hiện có sau khi cập nhật trình biên dịch về phía người dùng . Các tính năng không có gì, nhưng tất cả về quyết định phá vỡ hoặc không phá vỡ bản dựng.

Nó hoàn toàn tùy thuộc vào sở thích của bạn để sử dụng nó hay không. Tôi sử dụng nó mọi lúc vì nó giúp tôi sửa chữa lỗi lầm của mình.


19
Mặc dù không bắt buộc , nhưng chúng tôi khuyên bạn nên sử dụng chúng
Spikatrix

18
-Wall and -Werror was designed by code-refactoring maniacs for themselves.[cần dẫn nguồn]
YSC

22
Có vẻ như bạn đang mâu thuẫn với chính mình. Nếu bạn "sử dụng nó mọi lúc vì nó giúp sửa chữa [lỗi] của bạn", thì có đáng để dạy cho các lập trình viên mới hơn để họ sẽ thực hiện nó ở mọi nơi ngay từ đầu không? Tôi không nghĩ câu hỏi này là hỏi liệu có thể biên dịch mà không có hay không -Wall, và -Werrorchỉ hỏi liệu đó có phải là một ý tưởng hay không. Mà, từ câu cuối cùng của bạn, có vẻ như bạn đang nói nó.
scohe001

12
Khi bạn có thêm kinh nghiệm với việc duy trì mã không phải do bạn viết, hãy xem lại câu trả lời này.
Thorbjørn Ravn Andersen

Đây không phải là một câu trả lời hữu ích. Có 4 dấu hỏi trong câu hỏi OP. Có bao nhiêu câu trả lời này trả lời?
Anders
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.