[Học lập trình C++] Chương 1: 1.11a – Debugging chương trình của bạn (quan sát biến và call stack)

1.11a – Debugging chương trình của bạn (quan sát biến và call stack)
Trong phần trước bạn đã học làm sao sử dụng trình gỡ rối để quan sát quá trình thực hiện trong suốt chương trình. Tuy nhiên, chạy từng bước chương trình của bạn chỉ là một nửa những gì hữu ích của trình gỡ rối. Trình gỡ rối cũng để bạn quan sát giá trị của các biến theo từng bước trong code của bạn.
Ví dụ của chúng ta ở đây sẽ sử dụng trình gỡ rối của Visual Studio Express -- nếu bạn đang sử dụng IDE/debugger khác, lệnh có thể khác tên hoặc nằm ở vị trí khác.
Quan sát các biến
Quan sát biến là một quá trình xem xét kỹ giá trị của biến trong chương trình trong khi chương đang thực thi trong chế độ gỡ rối. Hầu hết các trình gỡ rối cung cấp nhiều cách để làm điều này. Hãy xem ví dụ sau:
#include "stdafx.h"
#include <iostream>
int main()
{
    int x(1);
    std::cout << x << " ";

    x = x + 1;
    std::cout << x << " ";

    x = x + 2;
    std::cout << x << " ";

    x = x + 4;
    std::cout << x << " ";

    return 0;
}

Đây là một chương trình dễ hiểu – nó in các giá trị 1, 2, 4, 8.
Đầu tiên sử dụng lệnh “Run to cursor” để debug dòng đầu tiên std::cout << x << “ ”; :
Tại điểm này, biến x đã được tạo và khởi tạo với giá trị 1, vì thế khi chúng ta kiểm tra giá trị của biến x, chúng ta sẽ mong đợi nhận được giá trị 1.
Cách dễ nhất để kiểm tra giá trị của biến đơn giống như x là di chuyển chuột vào biến x. Hầu hết trình gỡ rối hiện tại đều hỗ trợ phương pháp này của việc xem giá trị của biến, và đó là cách dễ hiểu nhất.
Chú ý rằng bạn có thể xem giá trị của bất kì biến nào, không chỉ một dòng hiện tại.
Nếu bạn đang sử dụng Visual Studio, bạn có thể sử dụng QuickWatch. Bôi đen biến x bằng chuột, và sau đó chọn “QuickWatch” từ menu phải chuột.
Nó sẽ xuất hiện của sổ chưa giá trị của biến:
Bây giờ hãy quan sát biến này thay đổi khi chương trình chạy từng bước. Đầu tiên chọn “Step over” hai lần, dòng kế tiếp được thực thi là std::cout << x << " ";
Biến x sẽ có giá trị là 2. Quan sát kĩ và chắc chắn rằng nó có giá trị đó.
Cửa sổ quan sát
Sử dụng chuột hoặc phương pháp QuickWatch để quan sát biến đều được nếu bạn muốn biến giá trị của biến tại thời điểm cụ thể. Những nó sẽ không thích hợp để xem giá trị của một biến thay đổi khi bạn chạy code bởi vì bạn tiếp tục phải di chuyển chuột vào hoặc chọn lại giá trị đó.
Để giải quyết vấn đề này, tất cả các trình biên dịch cung cấp một tính năng khác, gọi là cửa sổ quan sát, của sổ quan sát là một của sổ mà bạn có thể thêm biến mà bạn muốn tiếp tục quan sát, và những biến này sẽ được cập nhật khi qua mỗi bước mới của chương trình. Của sổ quan sát có thể là màn hình hiển thị khi bạn đi vào chế độ debug, nhưng nếu không, bạn có thể đưa nó ra ngoài IDE của bạn.
Trong Visual Studio 2005 Express, bạn vào Debug menu -> Windows -> Watch -> Watch 1 (chú ý: Bạn phải ở trong chế độ debug, vào step into chương trình của bạn trước)
Bạn sẽ thấy như sau:
Không có gì trong cửa sổ này bởi vì chúng ta chưa thiết lập. Thông thường có hai cách khác nhau để thiết lập:
1)    Gõ tên của tên biến bạn muốn xem trong cột “Name” của của sổ quan sát.
2)    Bôi đen biến mà bạn muốn quan sát, click phải chuột và chọn “Add watch”.
Tiếp tục và thêm biến x vào danh sách quan sát. Bạn sẽ nhìn thấy như sau:
Bây giờ chọn lệnh “Step over” một vài lần và quan sát giá trị của biến của bạn thay đổi!
Chú ý rằng biến đó ra khỏi scope (Ví dụ biến được khai báo trong một hàm, khi hàm đang chạy) sẽ ở trong của sổ quan sát của bạn. Nếu biên trả về scop (ví dụ: hàm được gọi một lần nữa), cửa sổ quan sát sẽ bắt đầu hiển thị giá trị của nó trở lại.
Sử dụng cửa sổ quan sát là cách tốt nhất để quan sát giá trị của một biến thay đổi theo thời gian khi bạn chạy chương trình từng bước.
Cửa sổ call stack
Trình gỡ rối hiện tại chưa nhiều hơn một cửa sổ thông tin debugging và đó có thể rất hữu ích trong debugging chương trình của bạn, và đó là call stack window.
Khi chương trình của bạn gọi một hàm, bạn đã biết rằng nó đánh dấu vị trí hiện tại, thực hiện hàm và sau đó trả về. Làm sau nó biết nơi nào để trả về? Câu trả lời là nó dựa vào call stack.
Call tack là một danh sách tất cả các hàm được kích hoạt mà được gọi để có được điểm thực thi hiện tại. Call stack bao gồm điểm đi vào cho mỗi hàm, bao gồm những dòng đang được kích hoạt. Bất cứ khi nào một hàm mới được gọi, hàm đó được thêm vào đỉnh của call stack. Khi hàm hiện tại trả về cho trình gọi, nó bị xóa đi từ đỉnh của call stack và điều khiển trả về cho hàm bên dưới nó.
Nếu bạn không thấy của sổ call stack, bạn sẽ cần phải nói với IDE để hiển thị nó. Trong Visual Studio 2005 Express, bạn có thể thực hiện điều này bằng cách vào Debug Menu -> Windows -> Call Stack (chú ý: bạn phải ở trong chế độ gỡ rối, vì vậy step into chương trình của bạn trước).
Hãy quan sát call stack sử dụng trong ví dụ sau:

#include "stdafx.h"
#include <iostream>

void CallC()
{
std::cout << "C called" << std::endl;
}
void CallB()
{
std::cout << "B called" << std::endl;
CallC();
}

void CallA()
{
CallB();
CallC();
}

int main()
{
CallA();

    return 0;
}

Đặt một breakpoint trong hàm CallC() và sau đó bắt đầu chế độ debugging. Chương trình sẽ thực cho tới khi gặp dòng lệnh được đánh dấu là breakpoint.
Mặc dù bạn biết rằng chương trình đang thực thi CallC(), thật ra có 2 lời gọi hàm CallC() trong chương trình (một trong hàm CallB(), và một trong CallA()). Hàm nào chịu trách nhiệm cho việc gọi CallC() thời điểm này? Call stack sẽ cho chúng ta thấy:
Chương trình bắt đầu bằng việc gọi hàm main(). Main() gọi hàm CallA(), hàm đó gọi CallB(), hàm này gọi hàm CallC(). Bạn có thể click đúp vào nhiều dòng trong cửa sổ Call stack để xem nhiều thông tin về gọi hàm. Một vài IDEs giúp bạn gọi hàm một cách trực tiếp. Khi bạn đã khôi phục lại code, click đúp vào dòng trên cùng của cửa sổ call stack và bạn sẽ trả lại cho bạn điểm thực thi.


Nguồn: learn.cpp

Nhận xét

Bài đăng phổ biến