สวัสดีและยินดีต้อนรับ.
ในการบรรยายนี้ ฉันต้องการพูดคุยเกี่ยวกับ call stack เล็กน้อย มันคืออะไรกันแน่ และคุณจะอ่านมันเพื่อช่วยดีบักโปรแกรมของคุณได้อย่างไร
การติดตามสแต็ก ซึ่งโดยพื้นฐานแล้วเป็นสิ่งที่เรียกว่าสแต็กการโทร จะถูกสร้างขึ้นเมื่อใดก็ตามที่แอปของคุณหยุดทำงานเนื่องจากข้อผิดพลาดร้ายแรง
เหตุผลที่ใช้คำว่า stack ก็เพราะว่ามันหมายถึงโครงสร้างข้อมูลที่พบได้ทั่วไปในการเขียนโปรแกรม
สแต็คเป็นโครงสร้างข้อมูลที่รู้จักกันในชื่อ LIFO เข้าก่อนออกก่อน และนั่นคือวิธีการจัดเก็บข้อมูล
องค์ประกอบข้อมูลสุดท้ายที่เพิ่มคือองค์ประกอบแรกที่คุณดึงกลับออกมา
คุณลองคิดดูสิว่าถ้าคุณกินแพนเค้กซ้อนกัน แพนเค้กชิ้นแรกจะอยู่ด้านล่างสุดที่คุณใส่ลงไป
แพนเค้กชิ้นสุดท้ายอยู่ด้านบน
เวลาไปกินก็กินอันสุดท้ายที่เพิ่มมา
ดังนั้นสแต็กเทรซจึงมีประโยชน์มากเมื่อโปรแกรมของคุณหยุดทำงาน เนื่องจากมีข้อมูลที่ช่วยคุณแก้ไขจุดบกพร่อง
ดังนั้นสแต็กเทรซจึงแสดงรายการการเรียกใช้ฟังก์ชันที่นำไปสู่ข้อผิดพลาด
และสิ่งที่จะเกิดขึ้นในโปรแกรมเมื่อคุณเรียกใช้ฟังก์ชันหลัก นั่นคือจุดเริ่มต้น
ฟังก์ชันหลักจะไปเรียกใช้ฟังก์ชันอื่นๆ
ฟังก์ชันเหล่านั้นจะเรียกใช้ฟังก์ชันอื่น ๆ และฟังก์ชันเหล่านั้นทั้งหมดที่ได้รับการนำไปใช้หรือถูกเรียกใช้จะถูกใส่ไว้ในสแต็ก
และที่คุณสามารถทำได้คือเมื่อโปรแกรมขัดข้อง call stack จะบอกคุณว่าฟังก์ชันสุดท้ายที่ถูกเรียกใช้และบรรทัดรหัสเฉพาะที่ทำให้เกิดข้อผิดพลาด
ดังนั้น Callstack จึงมีข้อมูลที่ดีมากมาย
โดยจะรวมชื่อไฟล์และหมายเลขบรรทัดของโค้ดที่ทำให้เกิดข้อยกเว้นหรือข้อผิดพลาดร้ายแรง
ด้านบนสุดของสแต็กประกอบด้วยการโทรล่าสุดที่ทำให้เกิดข้อผิดพลาด และอาจมีการโทรที่ซ้อนกัน
ด้านล่างของสแต็กประกอบด้วยการโทรแรกที่เริ่มต้นสายเรียกเข้าเพื่อเรียกข้อผิดพลาด
ดังนั้น ถ้าโดยปกติแล้วคุณอยู่ใน C ซึ่งจะอยู่ที่รูทีนหลัก คุณจะเรียกใช้ main, main จะเรียกใช้ฟังก์ชันอื่น ซึ่งเรียกใช้ฟังก์ชันอื่น
และอื่น ๆ ต่อ ๆ ไป
แล้วรายละเอียดบรรทัดสุดท้ายนั้น
มันมีประโยชน์มากเมื่อแอพสำหรับแอพขัดข้อง
ดังนั้นเมื่อโปรแกรม C ล่ม โปรแกรมอาจสร้างการแบ่งกลุ่มที่ผิดพลาด และนั่นไม่ได้บอกข้อมูลมากมายให้คุณทราบ
มันหมายถึงสิ่งที่ไม่ดีเกิดขึ้น
นั่นจะสร้างไฟล์หลักด้วย
คุณสามารถวิเคราะห์ไฟล์หลักที่มี call stack ซึ่งจะบอกบรรทัดรหัสที่แน่นอนที่ทำให้เกิดปัญหาสำหรับข้อขัดข้องของคุณ
ดังนั้นคุณต้องค้นหาการโทรในแอปพลิเคชันของคุณที่ทำให้เกิดข้อขัดข้อง
และคอลสแต็กน่าจะเป็นวิธีที่ดีที่สุดในการทำเช่นนี้
และคุณไม่จำเป็นต้องดูที่ไฟล์หลักนั้นเสมอไป
คุณยังสามารถวิเคราะห์ call stack ในการใช้ GDB ด้วยดีบักเกอร์
และฉันต้องการแสดงให้คุณเห็นว่ามันเป็นอย่างไร
โปรแกรมเมอร์ยังสามารถดัมพ์สแต็กเทรซได้ตลอดเวลา
ดังนั้น หากคุณพบข้อผิดพลาดหรือคุณทราบว่าอาจเกิดข้อผิดพลาดร้ายแรง คุณสามารถดัมพ์ call
stack เพื่อดูว่าเกิดอะไรขึ้น
หากคุณไม่ทราบว่าข้อผิดพลาดจะเกิดขึ้นเมื่อใด คุณยังสามารถดัมพ์
call stack เพื่อดูร่องรอยปัจจุบันที่นำไปสู่การโทรเฉพาะได้
เมื่อใช้ GDB call stack จะมีลักษณะดังนี้
คุณสามารถเข้าถึง call stack ผ่านทางเมนูเมื่อคุณเรียกใช้ดีบักเกอร์ใน GDB และฉันจะแสดงวิธีการทำ
แต่นี่คือลักษณะที่ปรากฏ และสิ่งที่คุณเห็นในที่นี้คือมีหมายเลข ที่อยู่และฟังก์ชัน
คอลสแต็กเฉพาะที่นี่มีการเรียกที่แตกต่างกันจำนวนมาก ดังนั้นจึงต้องทำการซ้อนที่แตกต่างกันจำนวนมากและการเรียกใช้ฟังก์ชันต่างๆ
มากมาย
แต่ที่ด้านล่างสุดของสแต็กในบรรทัดที่ 22 จะมีข้อความว่า GTK main
นั่นหมายถึง.
นั่นหมายความว่ามันอาจจะทำหน้าที่หลัก
จากนั้นในบรรทัดที่ 21 ดูเหมือนว่าจะดำเนินการ
บางทีคำสั่งบอกว่าการรันลูปหลัก
จากนั้นดูเหมือนว่าจะเรียกใช้ฟังก์ชันที่เรียกว่า G บริบทหลักวนซ้ำ
และภายในฟังก์ชันนั้น จะมีบางส่วนเมื่อใดก็ตามที่มีการเรียกใช้ฟังก์ชันการส่งบริบทหลักของ
IAG อีกครั้ง
ดังนั้นจึงมีฟังก์ชัน iterate ตามมาด้วยฟังก์ชัน dispatch และเครื่องหมายคำถามในบรรทัดที่
18 หมายความว่าไม่มีข้อมูลการดีบัก
มันไม่รู้ว่าเกิดอะไรขึ้นที่นั่น
และนั่นคือเหตุผลที่เมื่อคุณสร้างโปรแกรมของคุณ คุณสามารถสร้างโปรแกรมเพื่อเผยแพร่หรือสร้างด้วยข้อมูลการดีบักก็ได้
เมื่อคุณสร้างด้วยข้อมูลการดีบัก จะมีข้อมูลเพิ่มเติมเมื่อคุณคอมไพล์ ดังนั้นเมื่อคุณเรียกใช้
คุณสามารถดู call stack ได้
เมื่อคุณปล่อย ให้สร้างบางอย่างเพื่อปล่อย
โปรแกรมปฏิบัติการมีขนาดเล็กกว่ามากและอาจไม่มีข้อมูลนี้
อาจมีเครื่องหมายคำถามเพิ่มเติม
แต่สิ่งนี้จะบอกคุณด้วยหากคุณเรียกใช้ไลบรารีใดๆ โปรแกรมเพิ่มเติมใดๆ มันจะเรียกใช้สิ่งเหล่านั้นและจะบอกคุณถึง
call stack จากที่นั่น
แต่สิ่งที่แสดงให้เห็นอีกครั้งคือเหตุการณ์ที่ซ้อนกันที่แตกต่างกันสำหรับการโทรที่ด้านบนสุดคือสิ่งที่สำคัญ
เพราะนั่นจะบ่งบอกว่าอะไรเป็นสาเหตุของความผิดพลาด
ดูเหมือนว่าใน call stack นี้ การรีเฟรชภายในทำให้เกิดปัญหา
และคุณจะเห็นได้ว่าตั้งแต่บรรทัดที่ 22 ถึงบรรทัดที่ 0 มีการเรียกใช้รหัสที่แตกต่างกันมากมาย
แต่ในที่สุดโปรแกรมก็ขัดข้องใน line zero call stacks
คุณยังสามารถดู call stack ในขณะที่โปรแกรมกำลังทำงานเพื่อดูข้อมูลเพื่อให้คุณสามารถติดตามกลับได้
ดังนั้น หากคุณใส่เบรกพอยต์ภายในฟังก์ชัน คุณจะดีบัก คุณเรียกใช้ดีบักเกอร์ในนั้น
ดีบักเกอร์จะหยุดที่เบรกพอยต์นั้น
จากนั้นคุณสามารถเรียกใช้ call stack และมันจะบอกคุณว่าคุณไปถึงบรรทัดของรหัสนั้นได้อย่างไร
ฟังก์ชันนี้ถูกเรียกใช้ก่อนฟังก์ชันนี้
และอีกครั้ง โดยปกติจะเริ่มต้นด้วยฟังก์ชันหลัก
คุณยังสามารถสลับไปยังเฟรมต่างๆ ได้ หากคุณคุ้นเคยกับสแต็กและแนวคิด และวิธีที่มันอยู่ในหน่วยความจำ
คุณสามารถดูเฟรมต่างๆ ได้ แต่นี่เป็นเครื่องมือที่มีประโยชน์มากในการค้นหาข้อขัดข้องส่วนใหญ่ใน
C และมันง่ายมากที่จะ อ่าน.
หากคุณดูที่ด้านบนและคุณไม่เข้าใจเกี่ยวกับ call stack มากนัก คุณสามารถดูที่ด้านบนแล้วพูดว่า
โอ้ นั่นเป็นต้นตอ นั่นคือบรรทัดของโค้ดที่ทำให้เกิดข้อขัดข้อง
นี่เป็นตัวอย่างที่ดีที่ฉันพบบนเว็บ
เอ็กซีม่า
การศึกษา
ที่แสดงตัวอย่างสแตกการเรียกใช้ฟังก์ชัน
ดังนั้นหากเราดูตัวอย่างในโค้ด เช่น เราจะเห็นว่าเรามีโค้ดง่ายๆ
การคำนวณไม่สำคัญจริงๆ
โดยพื้นฐานแล้วเราแค่เรียกใช้ฟังก์ชันบางอย่าง
เรามีฟังก์ชัน mogrify และฟังก์ชัน half จริงๆ และ main จะเรียกฟังก์ชัน mogrify แล้วมันก็จะเรียกใช้
half จริงๆ แล้วมันก็จะ mogrify เพื่อให้เราสามารถแสดง call stack และสิ่งที่ดูเหมือนในการเรียกเหล่านี้
โดยพื้นฐานแล้วเพียงแค่ตั้งค่าเบรกพอยต์ง่ายๆ ใน main แล้วดูที่ call stack ขณะที่เราดำเนินการและโทรออก
อีกครั้ง เราจะทำความคุ้นเคยกับเบรกพอยต์และข้อมูลเช่นนั้นมากขึ้น
แต่ฉันแค่ต้องการสาธิต call stack อย่างรวดเร็ว และเราจะให้ตัวอย่าง call stack ที่มีรายละเอียดมากขึ้นในภายหลัง
ดังนั้นฉันจึงกำหนดเบรกพอยต์
ฉันสามารถไปข้างหน้า และสร้างและคอมไพล์สิ่งนี้ และเริ่มดีบักเกอร์ได้ และเราจะไปถึงเบรกพอยต์นั้น
และสิ่งที่คุณจะสังเกตเห็นตอนนี้ คุณจะเห็นเมนูดีบักเกอร์ทั้งหมดตรงนี้ทางขวามือด้านล่าง
และคุณจะเห็น call stack
มาทำให้มันใหญ่ขึ้นอีกหน่อย
แต่เมื่อหยุดที่บรรทัดที่ 14 ที่นี่จะมีแค่คำสั่งการมอบหมาย และคุณจะเห็นว่า
call stack แสดง main
ถ้าเราก้าวข้ามจุดนั้นและไปที่บรรทัดถัดไป เราจะเห็นว่ามันเพิ่งไปที่บรรทัดที่ 15 ก่อนที่มันจะเรียก
Mogrify ใช่ไหม?
คุณจึงเห็น call stack อยู่กับ Main
หากเราเข้าไปดู ตอนนี้คุณจะเห็นว่ากลุ่มการโทรแสดง Mogrify
เราอยู่ในฟังก์ชันนี้จริงๆ
เราสามารถก้าวข้ามสิ่งนั้นได้
มันรันบรรทัดแรกแล้วมันจะคืนค่า temp
มันยังคงอยู่ในฟังก์ชันนั้น และจากนั้นมันจะส่งกลับตำแหน่งที่มันพิมพ์ F ในบรรทัดที่ 16 คุณจะเห็นว่า call stack
เปลี่ยนไปอย่างไร
จากนั้นไปที่บรรทัดที่ 18 call stack ยังคงอยู่ที่ main และเราก้าวเข้าสู่ half function อย่างแท้จริง
และตอนนี้คุณจะเห็นการเปลี่ยนแปลงของ call stack ซึ่งแสดงฟังก์ชันครึ่งหนึ่งที่ด้านบนสุดว่าเป็นฟังก์ชันที่ถูกเรียกครั้งล่าสุดเสมอ
อีกครั้งที่เราก้าวข้ามและคุณจะเห็นว่าเรายังคงอยู่ในครึ่งจริงๆ
เรากลับไปที่ Main เราพิมพ์บางอย่างออกมาที่บรรทัดที่ 19 เราไปที่บรรทัดที่ 21
เราข้ามไปที่ฟังก์ชันแก้ไขอีกครั้ง ซึ่งคุณเห็นบน call stack อีกครั้ง เราข้ามไป เราข้ามไป และในที่สุดเราก็พิมพ์ผลลัพธ์สุดท้ายในบรรทัดที่
23 และส่งคืนจากโปรแกรม
แต่ call stack จะแสดงลำดับของฟังก์ชันที่ถูกเรียกใช้จากฟังก์ชันหนึ่งไปยังอีกฟังก์ชันหนึ่งอีกครั้ง
ดังนั้นหากคุณมีฟังก์ชันที่ซ้อนกัน มันอาจจะซับซ้อนขึ้นเรื่อยๆ
ข้อดีของ call stack คือถ้าคุณมีโค้ดบรรทัดที่ขัดข้อง เช่น ในบรรทัดที่สี่ คุณจะมี call
stack ที่มีโค้ดอยู่ด้านบนสุดที่บรรทัดนั้นขัดข้อง
ดังนั้นคุณจึงสามารถดูได้โดยการดู call stack ว่าโค้ดบรรทัดใดคือโค้ดสุดท้ายที่ถูกเรียกใช้
และนั่นจะบอกคุณว่าโค้ดบรรทัดใดที่ขัดข้อง
แต่คุณจะต้องใช้เครื่องมือนี้เมื่อโปรแกรมของคุณขัดข้อง
ขอบคุณ