Xin chào và chào mừng.
Trong bài giảng này, tôi muốn nói một chút về call stack, nó chính xác là gì và bạn có thể đọc
nó như thế nào để giúp gỡ lỗi chương trình của bạn.
Dấu vết ngăn xếp, về cơ bản là ngăn xếp cuộc gọi, được tạo bất cứ khi nào ứng dụng của bạn gặp
sự cố do lỗi nghiêm trọng.
Lý do thuật ngữ ngăn xếp được sử dụng là vì nó đề cập đến một cấu trúc dữ liệu phổ biến trong lập trình.
Ngăn xếp là một cấu trúc dữ liệu được gọi là LIFO, nhập sau, xuất trước và đó là cách dữ liệu được
lưu trữ.
Phần tử dữ liệu cuối cùng được thêm vào là phần tử đầu tiên mà bạn truy xuất lại.
Bạn có thể nghĩ về nó nếu bạn đang ăn một chồng bánh kếp, chiếc bánh kếp đầu tiên nằm ở dưới cùng
mà bạn thêm vào.
Chiếc bánh kếp cuối cùng ở trên cùng.
Khi bạn đi ăn chúng, bạn ăn cái cuối cùng được thêm vào.
Và do đó, dấu vết ngăn xếp rất hữu ích khi chương trình của bạn gặp sự cố vì nó chứa thông tin giúp
bạn gỡ lỗi.
Vì vậy, dấu vết ngăn xếp hiển thị danh sách các lệnh gọi hàm dẫn đến lỗi.
Và điều sẽ xảy ra trong một chương trình khi bạn gọi chức năng chính của mình, đó là điểm bắt đầu.
Chức năng chính sẽ gọi các chức năng khác.
Các chức năng đó sẽ gọi các chức năng khác và tất cả các chức năng được triển khai hoặc được
gọi sẽ được đưa vào ngăn xếp.
Và vì vậy bạn có thể làm là khi một chương trình gặp sự cố, ngăn xếp cuộc gọi sẽ cho bạn biết
chức năng cuối cùng được gọi và dòng mã cụ thể gây ra lỗi.
Vì vậy, Callstack chứa rất nhiều thông tin tốt.
Nó sẽ bao gồm tên tệp và số dòng của mã gây ra ngoại lệ hoặc lỗi nghiêm
trọng.
Phần trên cùng của ngăn xếp chứa lệnh gọi cuối cùng gây ra lỗi và có thể có các lệnh gọi lồng nhau.
Phần dưới cùng của ngăn xếp chứa lệnh gọi đầu tiên bắt đầu chuỗi lệnh gọi để gọi lỗi.
Vì vậy, nếu bạn thường ở trong C sẽ ở quy trình chính, bạn gọi hàm chính, hàm chính gọi hàm
khác, hàm này gọi hàm khác, v.v.
Và sau đó dòng cuối cùng là chi tiết.
Nó rất, rất hữu ích khi ứng dụng cho ứng dụng gặp sự cố.
Và do đó, khi chương trình C gặp sự cố, nó có thể tạo ra lỗi phân đoạn và điều đó không cho bạn biết nhiều
thông tin.
Nó chỉ có nghĩa là một cái gì đó xấu đã xảy ra.
Điều đó cũng sẽ tạo ra một tệp lõi.
Bạn có thể phân tích tệp lõi chứa ngăn xếp cuộc gọi, tệp này sẽ cho bạn biết dòng mã
chính xác đã gây ra sự cố cho sự cố của bạn.
Vì vậy, bạn cần tìm cuộc gọi trong ứng dụng của mình gây ra sự cố.
Và ngăn xếp cuộc gọi có lẽ là cách tốt nhất để làm điều này.
Và không phải lúc nào bạn cũng cần xem tệp cốt lõi đó.
Bạn cũng có thể phân tích ngăn xếp cuộc gọi trong GDB bằng cách sử dụng trình gỡ lỗi.
Và tôi muốn cho bạn thấy nó trông như thế nào.
Lập trình viên cũng có thể kết xuất dấu vết ngăn xếp bất kỳ lúc nào.
Vì vậy, nếu bạn bắt gặp một lỗi hoặc bạn nhận ra rằng một lỗi nghiêm trọng có thể xảy ra, bạn có thể kết xuất ngăn
xếp cuộc gọi để xem điều gì đang xảy ra.
Nếu bạn không thực sự biết khi nào lỗi sẽ xảy ra, bạn vẫn có thể kết xuất
ngăn xếp cuộc gọi để xem dấu vết hiện tại dẫn đến một cuộc gọi cụ thể.
Khi sử dụng GDB, ngăn xếp cuộc gọi sẽ giống như thế này.
Bạn có thể truy cập ngăn xếp cuộc gọi qua menu khi bạn đang chạy trình gỡ lỗi trong GDB và tôi sẽ chỉ
cho bạn cách thực hiện việc này, nhưng đây là giao diện của nó và những gì bạn sẽ thấy ở đây là nó có một số
, một địa chỉ và sau đó là chức năng.
Ngăn xếp cuộc gọi cụ thể này ở đây có rất nhiều cuộc gọi khác nhau, vì vậy nó phải thực hiện nhiều cách lồng nhau khác nhau
và nhiều cuộc gọi chức năng khác nhau.
Nhưng ở dưới cùng của ngăn xếp trong dòng 22, nó nói GTK chính.
Điều đó có nghĩa là.
Điều đó có nghĩa là nó có thể đã thực thi chức năng chính.
Và sau đó ở dòng 21, có vẻ như nó đã được thực thi.
Có thể một tuyên bố nói chạy vòng lặp chính.
Và sau đó có vẻ như được gọi là một chức năng được gọi là G lặp ngữ cảnh chính.
Và bên trong chức năng đó, có một số bất cứ khi nào có một cuộc gọi khác đến chức năng điều phối
bối cảnh chính của IAG.
Vì vậy, có một hàm lặp, sau đó là hàm điều phối và sau đó là các dấu chấm hỏi ở dòng 18 có
nghĩa là không có thông tin gỡ lỗi.
Nó không biết chuyện gì đã xảy ra ở đó.
Và đó là lý do tại sao khi bạn xây dựng chương trình của mình, bạn có thể xây dựng chương trình đó để phát hành hoặc bạn xây dựng
chương trình với thông tin gỡ lỗi.
Khi bạn xây dựng nó với thông tin gỡ lỗi, nó chứa thông tin bổ sung khi bạn biên dịch để khi bạn
chạy, bạn có thể xem ngăn xếp cuộc gọi.
Khi bạn phát hành nó, hãy xây dựng thứ gì đó để phát hành.
Tệp thực thi nhỏ hơn rất nhiều và có thể không chứa thông tin này.
Nó có thể chứa nhiều dấu hỏi hơn.
Nhưng điều này cũng sẽ cho bạn biết nếu bạn đã gọi bất kỳ thư viện nào, bất kỳ chương trình bổ sung nào, nó sẽ gọi những thư viện đó và
sẽ cho bạn biết ngăn xếp cuộc gọi từ đó.
Nhưng điều này cho thấy, một lần nữa, là các sự kiện lồng nhau khác nhau cho cuộc gọi ở trên cùng mới là điều
quan trọng, bởi vì điều đó sẽ biểu thị nguyên nhân gây ra sự cố.
Vì vậy, có vẻ như trong ngăn xếp cuộc gọi cụ thể này, quá trình làm mới bên trong đã gây ra sự cố.
Và bạn có thể thấy rằng từ dòng 22 đến dòng 0, có nhiều cách gọi mã khác
nhau.
Nhưng sự cố chương trình cuối cùng trong ngăn xếp cuộc gọi dòng không.
Bạn cũng có thể xem ngăn xếp cuộc gọi trong khi chương trình đang chạy để chỉ xem thông tin để bạn có thể theo
dõi lại.
Vì vậy, nếu bạn đặt một điểm ngắt bên trong một hàm, thì bạn gỡ lỗi, bạn chạy trình gỡ lỗi trên đó.
Trình gỡ lỗi sẽ dừng tại điểm dừng đó.
Sau đó, bạn có thể mở ngăn xếp cuộc gọi và nó sẽ cho bạn biết làm thế nào bạn có được dòng mã đó.
Chức năng này được gọi trước chức năng này.
Và một lần nữa, nó thường sẽ bắt đầu với chức năng chính.
Bạn cũng có thể chuyển sang các khung khác nhau nếu bạn quen thuộc với ngăn xếp và khái niệm cũng
như cách nó nằm trong bộ nhớ, bạn có thể xem xét các khung khác nhau, nhưng đây là một công cụ rất hữu ích để tìm
các sự cố chủ yếu trong C và rất dễ dàng để đọc.
Nếu bạn chỉ nhìn vào phần trên và bạn không hiểu nhiều về ngăn xếp cuộc
gọi, bạn có thể nhìn vào phần trên và nói, Ồ, đó là một nguồn, đó là một dòng mã gây ra sự cố.
Đây là một ví dụ hay mà tôi tìm thấy trên web.
Excma.
Edu.
Điều đó minh họa các ví dụ ngăn xếp lệnh gọi hàm.
Vì vậy, nếu chúng ta xem một ví dụ bằng mã như chúng ta sẽ thấy chúng ta chỉ có một số mã đơn giản.
Các tính toán không thực sự quan trọng.
Về cơ bản, chúng tôi chỉ gọi một số chức năng.
Vì vậy, chúng tôi có chức năng mogrify này và chức năng nửa thực sự này và chức năng chính sẽ gọi một hàm mogrify
và sau đó nó sẽ gọi thực sự một nửa và sau đó nó sẽ chuyển đổi để chúng tôi có thể minh họa
ngăn xếp lệnh gọi và giao diện của các lệnh gọi này về cơ bản, chỉ cần đặt một điểm dừng đơn giản trong chính
và sau đó xem ngăn xếp cuộc gọi khi chúng tôi tiến hành và thực hiện cuộc gọi.
Vì vậy, một lần nữa, chúng ta sẽ làm quen với breakpoint và những thông tin tương tự.
Nhưng tôi chỉ muốn chứng minh ngăn xếp cuộc gọi thật nhanh và chúng ta sẽ thực sự đưa ra một ví dụ chi tiết hơn
về ngăn xếp cuộc gọi sau.
Vì vậy, ở đây tôi đặt một điểm dừng.
Tôi có thể tiếp tục xây dựng và biên dịch cái này và tôi có thể khởi động trình gỡ lỗi và chúng ta sẽ đạt điểm dừng đó.
Và những gì bạn sẽ nhận thấy bây giờ là bạn có thể thấy tất cả menu trình gỡ lỗi ở đây, phía bên tay phải ở dưới cùng
và bạn sẽ thấy ngăn xếp cuộc gọi.
Hãy làm cho điều này lớn hơn một chút.
Nhưng ngay khi nó dừng ở dòng 14, ở đây nó chỉ có một số câu lệnh gán và bạn sẽ thấy ngăn xếp
cuộc gọi hiển thị chính.
Nếu chúng ta bước qua đó và chuyển sang dòng tiếp theo, chúng ta thực sự có thể thấy rằng nó chỉ chuyển đến dòng 15
trước khi gọi Mogrify, phải không?
Và vì vậy, bạn thấy ngăn xếp cuộc gọi vẫn ở với Chính.
Nếu chúng tôi bước vào, bây giờ bạn sẽ thấy ngăn xếp cuộc gọi hiển thị Mogrify.
Vì vậy, chúng tôi đang thực sự bên trong chức năng này.
Chúng ta có thể bước qua điều đó.
Vì vậy, nó thực thi dòng đầu tiên và sau đó nó sẽ trả về giá trị tạm thời.
Nó vẫn ở trong chức năng đó và sau đó nó trả về nơi nó in F trên dòng 16, bạn sẽ thấy ngăn xếp cuộc gọi đang thay
đổi như thế nào.
Sau đó, chúng tôi đi đến dòng 18, gọi stack stills trong main và chúng tôi bước vào chức năng thực sự một nửa.
Và bây giờ bạn thấy ngăn xếp cuộc gọi thay đổi trong đó nó hiển thị thực sự một nửa chức năng ở trên cùng
luôn là chức năng được gọi lần cuối.
Một lần nữa, chúng tôi bước qua và bạn thấy chúng tôi vẫn còn một nửa thực sự.
Chúng tôi quay lại Main, chúng tôi in một cái gì đó trên dòng 19, chúng tôi chuyển sang dòng 21.
Chúng tôi lại nhảy vào chức năng sửa đổi, mà bạn lại thấy trên ngăn xếp cuộc gọi, Chúng tôi nhảy qua, chúng tôi nhảy qua và cuối
cùng chúng tôi in ra kết quả cuối cùng ở dòng 23 và được trả về từ chương trình.
Nhưng ngăn xếp cuộc gọi một lần nữa cho chúng ta thấy thứ tự của các chức năng đang được gọi từ chức năng này sang chức năng tiếp
theo.
Vì vậy, nếu bạn có các hàm lồng nhau, nó có thể ngày càng phức tạp hơn.
Ưu điểm của ngăn xếp cuộc gọi là nếu bạn có một dòng mã bị lỗi, chẳng hạn như ở dòng bốn, thì bạn sẽ
có một ngăn xếp cuộc gọi chứa ở trên cùng nơi dòng đó bị lỗi.
Và do đó, bạn thực sự có thể thấy bằng cách xem qua ngăn xếp cuộc gọi, dòng mã nào là dòng cuối
cùng được gọi và dòng mã đó sẽ cho bạn biết dòng mã nào đã bị lỗi.
Nhưng bạn sẽ muốn sử dụng công cụ này khi chương trình của bạn gặp sự cố.
Cảm ơn.