2009-08-25 44 views
6

Có printfs, xác nhận, chỉnh sửa và tiếp tục, ghi nhật ký khung công tác? Whats chất độc yêu thích của bạn?Kỹ thuật gỡ lỗi yêu thích của bạn trong C++ là gì?

+8

Đó phải là cà phê. –

+6

Là một câu hỏi không có câu trả lời dứt khoát, đây phải là một wiki cộng đồng. – SPWorley

+0

Tôi xem đây là một bản sao, vì biến thể "C++" của bạn không xuất hiện để thêm nhiều: http://stackoverflow.com/questions/91527/debugging-techniques – gnovice

Trả lời

8

Nói chung, printf's. Chúng cho phép cắt chương trình dễ dàng và không yêu cầu bất kỳ công cụ nào ngoài trình soạn thảo và trình biên dịch.

+9

Chính xác. "Khi nghi ngờ, in ra nhiều hơn." –

+3

Họ cũng sẽ giúp bạn bỏ qua những điều khác đang xảy ra. IMHO gỡ lỗi bằng cách sử dụng in là phù hợp hơn cho các ngôn ngữ như PHP hoặc Python .... bằng cách sử dụng printf để 'gỡ lỗi' C++ ứng dụng giống như sử dụng ống nhòm để làm phẫu thuật. – jscharf

+0

@jscharf. Tôi không thể đồng ý nhiều hơn nữa! các điểm ngắt có điều kiện và khả năng xem các giá trị trong các biến tại mọi thời điểm là rất quan trọng. – rfcoder89

5

Tôi thích gdb - Tôi thường sử dụng nó trong chế độ dòng lệnh, nhưng, nếu bạn không thể đứng đó, có frontend GUI để nó như Insight, Ddd vv Logs luôn giúp đỡ, quá, và do đó, làm nòng cốt kết xuất các tệp mà bạn có thể thực hiện "gỡ lỗi sau khi gỡ lỗi" bằng các công cụ tương tự này.

13

Hệ thống ghi nhật ký đa cấp. Tôi thấy sử dụng trong ít nhất 5 cấp độ:

  • verbose: những thứ bạn chỉ muốn xem khi gỡ lỗi ở mức độ thấp thứ như lỗi giao thức; có thể được biên soạn từ các tệp nhị phân phát hành, do đó bạn có thể đặt nội dung ở cấp độ này mà bạn không muốn người dùng cuối tìm thấy

  • nội bộ: truy tìm cấp thấp hơn mức bình thường, thường hữu ích nhưng không quá thường xuyên mà bạn muốn nhìn thấy nó mọi lúc

  • bình thường: mức sản lượng mặc định, cho các công cụ hữu ích cho bất cứ ai xem hệ thống chạy bình thường

  • vấn đề: thời gian chạy lỗi rằng chương trình biết cách để đối phó với; bạn có thể chọn để chạy ở cấp độ này cho các phiên bản phát hành, thay vì bình thường

  • lỗi nghiêm trọng: "la hét và chết" thông điệp kiểu như out-of-bộ nhớ

Multi- mức ghi nhật ký cho phép bạn xây dựng nhiều thông tin đăng nhập vào chương trình mà không phải nhìn thấy nó mọi lúc. Bạn chỉ tăng cấp độ nhật ký khi bạn phải gỡ lỗi một cái gì đó, sau đó đặt nó trở lại mức bình thường của nó. Khi thực hiện gỡ lỗi kiểu "printf" - các thông báo tạm thời - tôi đặt chúng ở mức mức bình thường, vì vậy tôi không phải tăng cấp độ nhật ký để xem chúng và bị che khuất bởi số nội bộ ồn ào hoặc verbose thư cấp.

+2

Tôi thích cấp độ ** debug ** riêng cho các tin nhắn tạm thời. Mức gỡ lỗi là * luôn luôn * hiển thị. Điều này tránh "oh tôi không biết nếu nó sẽ hiển thị hay không, bất cứ điều gì tôi sẽ chỉ sử dụng' printf' cho thông điệp này "đào tạo của tư tưởng. Nó cũng phục vụ như một lời nhắc nhở rõ ràng để xóa bản in khi tôi đã hoàn thành gỡ lỗi. –

2

Tôi bỏ phiếu cho gdb. Đặc biệt là khi tất cả các bạn phải làm việc với là một tập tin cốt lõi.

printf đẹp khi bạn có ý tưởng chung về lỗi. Nhưng khi nhóm thử nghiệm quay trở lại với bạn với một tệp lõi và một mô tả kỳ lạ về vấn đề, để có thể phân tích kết xuất lõi sẽ cung cấp cho bạn một khởi đầu to lớn trong nỗ lực gỡ lỗi của bạn.

1

Truy tìm thông qua, sửa đổi các biến trong bộ nhớ để đạt được một số mã chi tiết không rõ ràng. Hiếm khi chỉnh sửa và tiếp tục, vì một lý do nào đó tôi không thể tin tưởng nó để giữ trạng thái lành mạnh, vì vậy toàn bộ hoạt động sau một thay đổi.

Khi không thể theo dõi (gdb trên cửa sổ là cách quá chậm ví dụ, nhấn một breakpoint mất 30 giây mỗi lần) sau đó printf. Junk mã và ném ra thời gian trong trường hợp lỗi đa luồng, nhưng đôi khi nó là cách duy nhất.

Trình gỡ rối trình gỡ rối khi phải gỡ lỗi bản phát hành bản phát hành mà không có thông tin gỡ lỗi (Olydbg rất hay khi hoạt động).

Ghi nhật ký phù hợp là tốt đẹp khi có sẵn, cần nỗ lực để thiết lập và sử dụng, nhưng rất có giá trị khi cần.

Gửi stacktraces nhà bị treo thậm chí còn đẹp hơn.

Các cảnh báo được lan truyền xung quanh nơi cần thiết.

Minidumps cho sự cố trên máy của người dùng. (Các lỗi treo có thể sao chép là tốt nhất. Nếu lỗi không thể dựa vào thời gian hiển thị thì có thể làm gì?)

2

Làm công cụ đa luồng, tôi không thể sống mà không cần đăng nhập. Để đăng nhập vào C++, tôi sử dụng the templog library. Nó cho phép một số mức độ nghiêm trọng (số lần đăng nhập nhiều lần () số lần nhiều mục tiêu nhật ký (có thể quan tâm đến nó?) kết hợp với nhiều bộ lọc nhật ký lọc (nơi viết nó?) bạn không bị chìm trong tiếng ồn. Nó đi một chặng đường dài hướng tới hiệu quả, sử dụng các công cụ mẫu meta để giúp trình biên dịch loại bỏ mã thừa trong khi không rơi vào bẫy assert(do_something_important()).

Ngoài ra, nó đủ nhỏ (tôi nghĩ rằng nó dưới 1kLoC trải rộng trên nửa tá tiêu đề) và đi kèm với giấy phép tăng cường cho phép để bạn không phụ thuộc vào người sáng tạo để không để cho quả bóng rơi xuống. Nếu họ làm - bạn chỉ có thể tự duy trì nó.

Tôi chỉ mong các chàng trai cuối cùng sẽ biến nhánh đó thành mã hiện tại nằm trong thân cây mới.

1

Đối với điều này, tôi sẽ phải đi với cố ý cấu trúc dự án để giảm thiểu thời gian xây dựng/lặp lại gia tăng. Là một tác dụng phụ, đây là những bước tương tự cần thiết để giữ cho chỉnh sửa và tiếp tục hoạt động bình thường.

1

Xác nhận. Khi tôi viết mã, nếu tôi phát hiện ra bất kỳ trường hợp cạnh nào mà tôi nghĩ có thể cho thấy sự cố, tôi có thể thả vào một dòng mà sẽ cho tôi biết khi gỡ lỗi xây dựng nếu một điều như vậy đang xảy ra. Đối với điểm thưởng, chúng không có hiệu quả về hiệu suất trên bản phát hành để bạn có thể kiểm tra những thứ đắt tiền như ví dụ. Rõ ràng chúng không phải là một sự thay thế để kiểm tra các điều kiện lỗi thực sự mà bạn phải nắm bắt, nhưng chúng tuyệt vời cho những trường hợp rìa nơi bạn nghĩ "có lẽ tôi nên kiểm tra" trong khi bạn đang viết mã.

+0

Nếu bạn nghĩ rằng 'có lẽ tôi nên kiểm tra xem' tại bất kỳ điểm nào trong quá trình xây dựng phát triển mà không có kiểm tra đó (thông qua biên soạn phát hành hoặc khác) đang mở ra một cánh cửa cho sự cố xuống dòng. – ezpz

0

Viết cẩn thận để tôi giảm thiểu việc tạo lỗi ở nơi đầu tiên.

Khi tôi có lỗi, tôi thích IDE và bước qua mã.

Printfs là một công cụ cực kỳ mạnh mẽ, nhưng vẫn là vũ khí cuối cùng.

6

biện pháp phản hồi:

  • Sử dụng một trình gỡ lỗi tốt, đặc biệt là sự đa dạng tích hợp. Sử dụng trình gỡ lỗi hoạt động trực quan với mã của bạn.

  • Chiến thuật gỡ lỗi. Quen thuộc với các công cụ của bạn. Kiến thức về những cạm bẫy phổ biến. Quá trình khấu trừ. Sử dụng giả thuyết và phân nhánh về các ý tưởng khác nhau ..quay trở lại ý tưởng trước đó khi cần. Theo dõi tiến trình gỡ lỗi của bạn. Phương pháp khoa học.

  • Công cụ phân tích (ví dụ: Dependancy Walker, .NET Reflector), bãi bộ nhớ, dấu vết ngăn xếp và nhật ký.

biện pháp phòng ngừa:

  • gia tăng nhỏ được xây dựng. Trong quá trình phát triển tích cực, hãy thêm vào dự án của bạn từng mảnh và kiểm tra từng phần đến. Không phun ra một loạt các mã và sau đó mash Run và blithely sửa từng lỗi. Thêm vào từng phần chương trình của bạn và dành thời gian sửa mọi thứ. Cố gắng làm cho từng gia tăng trong dự án của bạn 'nguyên tử'.

  • Ghi nhật ký đa cấp, như những người khác đã chỉ ra. Có một quy mô nghiêm trọng chạy từ theo dõi đến lỗi nghiêm trọng và tất cả mọi thứ ở giữa. Ứng dụng sản xuất của bạn nên ghi lại mọi thứ duy nhất mà nó thực hiện và tại sao nó thành công hay thất bại, nhưng bạn cũng có thể thay đổi mức ghi nhật ký khi không cần đến mức chi tiết cực đoan. Nhật ký phải là con người có thể đọc được như là ưu tiên hàng đầu.

  • Ghi nhật ký không an toàn. Không phụ thuộc vào cơ chế đăng nhập của bạn để tồn tại các tình huống đặc biệt. Luôn có kế hoạch sao lưu - nhật ký sự kiện, tệp văn bản phẳng, email mương cuối cùng - khi mọi thứ diễn ra.

  • Chính sách kiểm soát nguồn tốt. Thường xuyên kiểm tra trong một lịch trình thường xuyên ở mức tối thiểu, cộng với check-in cho bất kỳ và tất cả các nhóm thay đổi, đặc biệt là phổ biến rộng rãi hoặc có thể phá vỡ những thay đổi.

18

khẳng định khẳng định khẳng định.

Tôi có 300000 loc (không kể nhận xét) về mã được sử dụng nhiều và được sử dụng lại trong thư viện cá nhân của mình, trong đó khoảng 15% (đoán) là mẫu và 50000 loc là mã thử nghiệm.

Nếu thành ngữ trùng lặp thì nó được tạo thành một hàm/phương thức. Cá nhân tôi xem dễ dàng cắt và dán như sáng chế của DEVIL cố tình đặt ở đó để mã bloat và tuyên truyền các khuyết tật.

Khoảng 4% thư viện là ASSERTS và mã gỡ lỗi (rất ít printfs và gần như tất cả đầu ra được xếp hàng đợi cho một tác vụ ưu tiên thấp tùy chỉnh luồng vì màn hình IO quá đắt và do đó việc thay đổi thời gian). Có lẽ 50% của các xác nhận là có để đảm bảo bất biến lớp và các điều kiện bài về thực hiện phương pháp.

Tôi tái cấu trúc một cách mecilessly khi tôi xem lại một đoạn mã mà tôi có thể vội vã hoặc có thể mắc lỗi trong thiết kế giao diện/đối tượng, nói đối tượng chủ thể của một phương thức thực sự thuộc về đối tượng đối tượng và phương thức thuộc về trong một đối tượng ban đầu (đối tượng tham số). Tự do với những lời khẳng định dường như bảo vệ tôi khỏi một số sai lầm ngớ ngẩn nếu tôi thực hiện tái cấu trúc đáng kể. Điều này không xảy ra nhiều nhưng có những lúc.

Tôi có một macro gỡ rối đóng vai trò giống như ASSERT vì vậy tôi có thể có mã bao quanh bởi

gỡ rối (... mã ....);

và không được biên dịch trong các bản dựng không gỡ lỗi.

Tôi không sử dụng xác nhận do nhà cung cấp cung cấp.Lời khẳng định của tôi KHÔNG hủy bỏ & kết xuất lõi mà chỉ đơn thuần là ném lên một hộp thông báo và gọi trình gỡ rối. Nếu đó là mã mới và phương thức là phương thức const, có thể quay trở lại phương thức và sau đó thực hiện lại phương thức đó (phương thức) với cùng một tập các tham số khá hữu ích. Đôi khi thậm chí thực tế là một số dữ liệu được thay đổi là không liên quan đến vấn đề và người ta có thể gọi lại với sự hiểu biết về kiến ​​thức.

Tôi hoàn toàn là trình gỡ rối dòng lệnh HATE. Nó giống như quay trở lại 25 năm trong thời gian - cũng có thể được sử dụng một teletype và một đường dây 2400 baud. Tôi cần và muốn có một IDE đầy đủ, nơi người ta có thể nhấp chuột phải vào một cấu trúc dữ liệu và mở nó lên, đóng nó lại, các con trỏ theo đuổi thực hiện các phương thức vv…

Tôi duyệt qua từng dòng mã mới và kiểm tra mọi (một trong các biến của tôi) cho hành vi mong đợi. Việc sử dụng một IDE làm nổi bật những thay đổi là vô giá ở đây. Để làm điều đó với GDB người ta phải là một nghệ sĩ dương cầm hòa nhạc với ký ức về Carnac the Magnificent ;-).

Để phát triển mới, tôi cũng cố gắng thu thập dữ liệu luồng/dữ liệu tin nhắn khi gặp phải tình trạng bất thường. Điều này đặc biệt hữu ích cho các máy chủ udp và thường xuyên bắt đầu khả năng tái tạo.

Tôi cũng thích có trình mô phỏng có thể "bao quanh ứng dụng và điều khiển nó và tiêu thụ nó và thực hiện xác minh" (hầu hết các mã của tôi là không đầu hoặc ít nhất là tương tác của con người là Tôi thấy rất quan trọng để có sự hỗ trợ và quản lý tốt, hiểu rằng việc tạo ra dữ liệu thử nghiệm là rất quan trọng và việc thu thập dữ liệu thử nghiệm là những gì tích hợp vào một bộ kiểm thử

Tôi cũng đã từng muốn thiết lập cách thức lượng tử lập lịch trình hệ điều hành xuống Với các ứng dụng đa luồng như lượng tử ngắn như vậy có thể dễ dàng đưa ra lỗi luồng hơn. bject phương pháp với nhiều chủ đề - hàng chục nếu không phải hàng trăm. Nói chung một đối tượng threadsafe không thể được kiểm tra tại chỗ nếu ứng dụng được điều khiển bởi con người - chỉ impposible để lái nó. Vì vậy, có nhu cầu thực sự cho các trình điều khiển thử nghiệm tùy chỉnh ở mức thấp hơn nhiều (theo định hướng thành phần). Và trong thử nghiệm này, các xác nhận có thể cho bạn biết nếu có điều gì đó bị phá vỡ. Rõ ràng là không chứng minh mã là đúng nhưng không cho một số sự tự tin.

Điều này cũng đúng là các tùy chọn này có thể phản ánh các quan điểm và vai trò được định hướng nhiều hơn về thư viện/lớp học mà tôi đã có. Khi bạn viết mã thư viện, thường có rất ít vấn đề "sản xuất" vì thư viện được định nghĩa nhiều và được kiểm tra rất nhiều. Việc ghi nhật ký và loại lịch sử đó dường như có định hướng ứng dụng nhiều hơn là định hướng thư viện.

+2

wow, tốt, tôi thích câu trả lời đó – knittl

+1

Đồng ý ở mọi nơi (đặc biệt là khẳng định tùy chỉnh) ngoại trừ nhận xét về gdb; dễ sử dụng là thuộc tính có được, không phải là thuộc tính được kế thừa. Trong khi một giao diện trực quan cung cấp cho một khoảng thời gian lớn hơn của dữ liệu hiển thị nó không vốn cung cấp tiện ích lớn hơn. – ezpz

0

Nếu bạn đang sử dụng Trình gỡ lỗi Visual Studio (mà tôi nghi ngờ bạn là vì bạn đã đề cập 'chỉnh sửa và tiếp tục'), bạn có thể sử dụng tốt "Cửa sổ ngay lập tức". Bạn có thể nhanh chóng đưa nó lên bằng phím tắt Ctrl + Alt + I

'Cửa sổ ngay lập tức' tương đối gần với vòng lặp "Đọc-đánh giá", phổ biến trong ngôn ngữ động, nhưng tất cả nhưng không có bằng ngôn ngữ C++ và các ngôn ngữ tương tự. Cửa sổ ngay lập tức sẽ cho phép bạn đánh giá các biểu thức đơn giản mà bạn cũng có thể thực hiện trong cửa sổ đồng hồ, nhưng cũng cho phép bạn chạy các câu lệnh đơn giản, cửa sổ xem không tốt.

Nếu có một số giả thuyết bạn muốn khám phá trong khi gỡ lỗi, thực hiện các thử nghiệm trong cửa sổ ngay lập tức thường có thể đưa bạn đến các câu trả lời một cách nhanh chóng. Bạn không cần phải biết trước những gì bạn cần in, bạn sẽ có tất cả thông tin trạng thái bạn cần có sẵn cho bạn trong khi bạn đang ở trong trình gỡ lỗi. Và bạn có thể thay đổi trạng thái chương trình của mình bằng cách thực hiện các câu lệnh đơn giản để kiểm tra giả thuyết của bạn, một điều bạn không thể làm với các câu lệnh in đơn giản.

Gỡ lỗi theo cách này giống như kiểu lập trình gia tăng phổ biến trong các ngôn ngữ cung cấp REPL ngoài hộp (như nói Python hoặc Ruby). Nó có thể khá hữu ích trong việc gỡ lỗi của bạn.

1

Tiếp theo đăng nhập, một kỹ thuật tốt đẹp đã giúp chúng tôi bán phá giá tất cả các biến hữu ích theo cách có thể đọc theo yêu cầu. Bằng cách này, bạn có thể thu hẹp các nguyên nhân có thể xảy ra.

1

IMO một trong những cách mạnh mẽ nhất để gỡ lỗi mã máy chủ là Gỡ lỗi vi sai, đó là so sánh hai tệp nhật ký.

Điều này đặc biệt hữu ích với mã cũ khi các nhà phát triển hiện tại không biết tất cả các vùng của mã. Nó giúp thu hẹp khu vực tìm kiếm và mã phải được phân tích. Nó đòi hỏi phải đăng nhập tốt/truy tìm để có mặt.

Tính năng này hoạt động khi bạn có trường hợp sử dụng thành công và trường hợp không thành công. Ví dụ tính năng X được sử dụng để làm việc trong phiên bản 3 của sản phẩm của bạn nhưng bây giờ bị hỏng trong phiên bản 4, và không ai biết tại sao.

Hãy so sánh các bản ghi, sử dụng awk hoặc sed để loại bỏ sự khác biệt cần thiết (các kịch bản có thể được tái sử dụng):

  • Time tem
  • ID Chủ đề - đôi khi lọc trên một chủ đề cụ thể
  • đường
  • vv

Khi bạn thấy phân tách nhật ký, điều này thường cho thấy một quyết định sai đã được thực hiện chỉ b efore.

Tôi đã sử dụng kỹ thuật này để thay thế một giải pháp phần mềm trung gian độc quyền trong một hệ thống cũ với CORBA và đảm bảo rằng tôi không thay đổi hành vi của logic ứng dụng. Nhưng nó rất hữu ích trong nhiều tình huống.

0

Nếu chương trình của tôi quá lớn, tôi phải tách riêng phần vấn đề và gỡ lỗi một cách độc lập. Nó tạo cơ hội cho mã có nhiều kiểu mô-đun hơn.

0

Chế độ Emacs gud-gdb là một con dao của quân đội swiss!

Tôi không còn đứng chế độ consb gdb nữa, tôi biết ai đang làm, nhưng trong trường hợp của tôi sử dụng trình gỡ lỗi GUI bất cứ khi nào nó có thể chỉ đáng giá.

IDA PRO là điều khác, tôi có thể sử dụng nó quá bất cứ lúc nào khi nói đến (RE)

0

Đừng quên valgrind ... nó lưu bacon của tôi trên nhiều hơn một lần bằng cách giúp tìm thấy che khuất một lần trong 100-chạy bộ nhớ tham nhũng hoặc lỗi uninitialized-giá trị.

3

Tôi sử dụng lệnh gdb commands để tạo báo cáo "printf" khi đang di chuyển. Chỉ cần chắc chắn rằng lệnh cuối cùng là tiếp tục.

#assume two breakpoints, 1 and 2 
commands 1 
    silent 
    echo calling baz\n 
    set $print_foobar=1 
    continue 
end 

commands 2 
silent 
    echo calling foobar\n 
    if $print_foobar 
    set $print_foobar=0 
    backtrace 
    end 
    continue 
end 

Gần đây tôi đã yêu kỹ thuật này vì nó cho phép tôi tạo câu lệnh printf() cho mã đang chạy. Plus GDB scripting mặc dù hạn chế cho phép bạn làm khá một chút khi quyết định những gì để in. Tôi chưa tìm thấy một tình huống mà một phần lệnh không tốt hay tốt hơn một số printf().

-1

Khi viết mã, hãy xem xét làm thế nào bạn đang đi để được đặt breakpoint ở đó sau này. Điều này đặc biệt có nghĩa là không lạm dụng các cuộc gọi hàm lồng nhau - foo(bar(baz)) - và tương tự đối với các chuỗi trường/phương thức - foo().bar().baz(). Nói chung, trừ khi các biểu thức là tầm thường, thường có giá trị để đặt chúng trên các dòng riêng biệt và gán chúng cho các biến, ngay cả khi các giá trị chỉ được sử dụng một lần - sau đó bạn có thể dễ dàng thực hiện từng bước, đặt điểm ngắt chính xác nơi bạn muốn và bạn sẽ có các giá trị xung quanh trong cửa sổ xem. Khi biên dịch với tối ưu hóa, bất kỳ biến nào như vậy có thể sẽ được tối ưu hóa, đặc biệt nếu bạn sử dụng mẹo tham chiếu const thay vì dựa vào RVO để khởi động.

Các vấn đề liên quan