ดูเหมือนว่าฉันได้รับแนวคิดของcall stackในการออกแบบภาษาโปรแกรม แต่ฉันไม่สามารถหาได้ (อาจเป็นไปได้ว่าฉันแค่ค้นหาไม่หนักพอ) คำอธิบายที่เหมาะสมเกี่ยวกับสแต็คเฟรมคืออะไร
ดังนั้นฉันอยากจะขอให้ใครบางคนอธิบายให้ฉันด้วยคำไม่กี่คำ
ดูเหมือนว่าฉันได้รับแนวคิดของcall stackในการออกแบบภาษาโปรแกรม แต่ฉันไม่สามารถหาได้ (อาจเป็นไปได้ว่าฉันแค่ค้นหาไม่หนักพอ) คำอธิบายที่เหมาะสมเกี่ยวกับสแต็คเฟรมคืออะไร
ดังนั้นฉันอยากจะขอให้ใครบางคนอธิบายให้ฉันด้วยคำไม่กี่คำ
คำตอบ:
กรอบสแต็กเป็นเฟรมของข้อมูลที่ถูกส่งไปยังสแต็ก ในกรณีของ call stack เฟรมสแต็กจะแทนการเรียกใช้ฟังก์ชันและข้อมูลอาร์กิวเมนต์
ถ้าฉันจำได้อย่างถูกต้องที่อยู่ที่ส่งคืนของฟังก์ชันจะถูกส่งไปยังสแต็กก่อนจากนั้นจึงหาข้อโต้แย้งและพื้นที่สำหรับตัวแปรโลคัล เมื่อรวมเข้าด้วยกันพวกมันสร้าง "เฟรม" แม้ว่าสิ่งนี้จะขึ้นอยู่กับสถาปัตยกรรม โปรเซสเซอร์รู้จำนวนไบต์ในแต่ละเฟรมและเลื่อนตัวชี้สแต็กตามที่เฟรมถูกผลักและแตกออกจากสแต็ก
มีความแตกต่างอย่างมากระหว่างสแต็กการโทรระดับสูงและการสแต็กการเรียกของโปรเซสเซอร์
เมื่อเราพูดถึง call stack ของโปรเซสเซอร์เรากำลังพูดถึงการทำงานกับ address และค่าที่ระดับbyte / wordในแอสเซมบลีหรือรหัสเครื่อง มี "call stacks" เมื่อพูดถึงภาษาระดับสูงกว่า แต่เป็นเครื่องมือดีบัก / รันไทม์ที่จัดการโดยสภาพแวดล้อมรันไทม์เพื่อให้คุณสามารถบันทึกสิ่งที่ผิดพลาดกับโปรแกรมของคุณ (ในระดับสูง) ในระดับนี้สิ่งต่าง ๆ เช่นหมายเลขบรรทัดและเมธอดและชื่อคลาสมักเป็นที่รู้จัก เมื่อโปรเซสเซอร์ได้รับโค้ดมันก็ไม่มีแนวความคิดเกี่ยวกับสิ่งเหล่านี้
ถ้าคุณเข้าใจ stack ได้ดีแล้วคุณจะเข้าใจว่าหน่วยความจำทำงานอย่างไรในโปรแกรมและถ้าคุณเข้าใจว่าหน่วยความจำทำงานอย่างไรในโปรแกรมคุณจะเข้าใจว่า function store ในโปรแกรมและถ้าคุณเข้าใจว่า function store ในโปรแกรมคุณจะเข้าใจว่า คุณเข้าใจว่าฟังก์ชั่น recursive ทำงานอย่างไรคุณจะเข้าใจว่าคอมไพเลอร์ทำงานอย่างไรและถ้าคุณเข้าใจว่าคอมไพเลอร์ทำงานอย่างไรใจของคุณจะทำงานเป็นคอมไพเลอร์และคุณจะดีบักโปรแกรมใด ๆ ได้อย่างง่ายดาย
ให้ฉันอธิบายว่าสแต็คทำงานอย่างไร:
ก่อนอื่นคุณต้องรู้วิธีการแสดงฟังก์ชั่นในกองซ้อน:
กองเก็บค่าที่ปันส่วนแบบไดนามิก
สแต็คเก็บค่าการจัดสรรและการลบอัตโนมัติ
มาทำความเข้าใจกับตัวอย่าง:
def hello(x):
if x==1:
return "op"
else:
u=1
e=12
s=hello(x-1)
e+=1
print(s)
print(x)
u+=1
return e
hello(4)
ตอนนี้เข้าใจบางส่วนของโปรแกรมนี้:
ทีนี้มาดูสแต็คคืออะไรและอะไรคือสแต็กชิ้นส่วน:
การจัดสรรสแต็ก:
โปรดจำไว้ว่ามีสิ่งหนึ่งที่: หากเงื่อนไขการส่งคืนของฟังก์ชันใด ๆ ได้รับการตอบสนองไม่ว่าจะโหลดตัวแปรท้องถิ่นหรือไม่ก็ตามมันจะส่งคืนจากสแต็กทันทีด้วยสแต็กเฟรม หมายความว่าเมื่อใดก็ตามที่ฟังก์ชั่นวนซ้ำได้รับความพึงพอใจของสภาพฐานและเรากลับมาหลังจากเงื่อนไขพื้นฐานสภาพฐานจะไม่รอโหลดตัวแปรท้องถิ่นที่อยู่ในส่วน "อื่น" ของโปรแกรม มันจะส่งคืนเฟรมปัจจุบันจากสแต็กทันทีซึ่งเฟรมถัดไปอยู่ในระเบียนการเปิดใช้งานทันที
ดูสิ่งนี้ในทางปฏิบัติ:
การยกเลิกการจัดสรรบล็อก:
ดังนั้นเมื่อใดก็ตามที่ฟังก์ชันพบคำสั่ง return มันจะลบเฟรมปัจจุบันออกจากสแต็ก
ในขณะที่ส่งคืนจากสแต็กค่าจะส่งกลับในลำดับเดิมที่ถูกจัดสรรในสแต็ก
hello()
เรียกซ้ำแล้วซ้ำอีกhello()
ซึ่งเรียกอีกครั้ง (อีกครั้ง) เรียกซ้ำhello()
และเฟรมทั่วโลกเป็นฟังก์ชั่นดั้งเดิมซึ่งเรียกว่าครั้งแรกhello()
?
สรุปอย่างรวดเร็ว อาจมีบางคนมีคำอธิบายที่ดีกว่า
สแตกการโทรประกอบด้วย 1 หรือหลายเฟรมสแต็กจำนวนมาก แต่ละเฟรมสแต็กสอดคล้องกับการเรียกไปยังฟังก์ชันหรือกระบวนงานที่ยังไม่สิ้นสุดด้วยการส่งคืน
ในการใช้สแต็กเฟรมเธรดจะเก็บตัวชี้ไว้สองตัวตัวหนึ่งเรียกว่า Stack Pointer (SP) และอีกตัวเรียกว่า Frame Pointer (FP) SP จะชี้ไปที่ "ด้านบน" ของสแต็กเสมอและ FP จะชี้ไปที่ "ด้านบน" ของเฟรมเสมอ นอกจากนี้เธรดยังคงรักษาตัวนับโปรแกรม (PC) ซึ่งชี้ไปที่คำสั่งถัดไปที่จะดำเนินการ
ข้อมูลต่อไปนี้ถูกเก็บไว้ในสแต็ก: ตัวแปรท้องถิ่นและเทมเพลตพารามิเตอร์ที่แท้จริงของคำสั่งปัจจุบัน (โพรซีเดอร์ฟังก์ชัน ฯลฯ )
มีข้อกำหนดการโทรที่แตกต่างกันเกี่ยวกับการล้างสแต็ก
"สแตกการโทรประกอบด้วยสแต็กเฟรม ... " - Wikipedia
เฟรมสแต็กเป็นสิ่งที่คุณวางลงบนสแต็ก มันเป็นโครงสร้างข้อมูลที่มีข้อมูลเกี่ยวกับรูทีนย่อยที่จะเรียก
โปรแกรมเมอร์อาจมีคำถามเกี่ยวกับกรอบสแต็คไม่ได้อยู่ในคำกว้าง (ว่ามันเป็นนิติบุคคลไหม้ในกองที่ทำหน้าที่เพียงหนึ่งในสายงานและช่วยให้ที่อยู่ผู้ส่งข้อโต้แย้งและตัวแปรท้องถิ่น) แต่ในความหมายแคบ - เมื่อคำที่stack frames
ถูกกล่าวถึงใน บริบทของตัวเลือกคอมไพเลอร์
ไม่ว่าผู้เขียนคำถามมีความหมายหรือไม่ แต่แนวคิดของกรอบสแต็กจากแง่มุมของตัวเลือกคอมไพเลอร์เป็นปัญหาที่สำคัญมากไม่ครอบคลุมโดยคำตอบอื่น ๆ ที่นี่
ตัวอย่างเช่นคอมไพเลอร์ Microsoft Visual Studio 2015 C / C ++ มีตัวเลือกต่อไปนี้ที่เกี่ยวข้องกับstack frames
:
GCC มีดังต่อไปนี้:
Intel C ++ Compiler มีดังต่อไปนี้:
ซึ่งมีนามแฝงต่อไปนี้:
Delphi มีตัวเลือกบรรทัดคำสั่งต่อไปนี้:
ในแง่ที่เฉพาะเจาะจงนั้นจากมุมมองของคอมไพเลอร์เฟรมสแต็คเป็นเพียงรายการเข้าและออกจากรหัสสำหรับรูทีนที่ดันสมอไปยังสแต็ก - ซึ่งยังสามารถใช้สำหรับการดีบักและสำหรับการจัดการข้อยกเว้น เครื่องมือการดีบั๊กอาจสแกนข้อมูลสแต็กและใช้จุดยึดเหล่านี้เพื่อ backtracing ขณะที่ค้นหาcall sites
ในสแต็กเช่นเพื่อแสดงชื่อของฟังก์ชันตามลำดับที่ถูกเรียกแบบลำดับชั้น สำหรับสถาปัตยกรรม Intel มันเป็นpush ebp; mov ebp, esp
หรือenter
สำหรับรายการและmov esp, ebp; pop ebp
หรือleave
สำหรับทางออก
นั่นเป็นเหตุผลว่าทำไมจึงเป็นเรื่องสำคัญมากที่ต้องเข้าใจโปรแกรมเมอร์ว่าสแต็กเฟรมอยู่ในตัวเลือกคอมไพเลอร์เพราะคอมไพเลอร์สามารถควบคุมว่าจะสร้างโค้ดนี้หรือไม่
ในบางกรณีสแต็กเฟรม (โค้ดเข้าและออกสำหรับรูทีน) สามารถละเว้นได้โดยคอมไพเลอร์และตัวแปรจะเข้าถึงได้โดยตรงผ่านตัวชี้สแต็ก (SP / ESP / RSP) แทนตัวชี้ฐานที่สะดวก (BP / ESP / RSP) เงื่อนไขสำหรับการละเว้นของกรอบสแต็กเช่น:
การข้ามเฟรมสแต็ก (รายการและรหัสออกสำหรับรูทีน) สามารถทำให้โค้ดมีขนาดเล็กลงและเร็วขึ้น แต่ก็อาจส่งผลเสียต่อความสามารถของผู้ debuggers ในการย้อนกลับข้อมูลในสแต็กและแสดงให้โปรแกรมเมอร์ นี่คือตัวเลือกคอมไพเลอร์ที่กำหนดภายใต้เงื่อนไขว่าฟังก์ชันควรมีรายการและรหัสทางออกตัวอย่างเช่น: (a) เสมอ, (b) ไม่เคย, (c) เมื่อจำเป็น (ระบุเงื่อนไข)
Stack frame เป็นข้อมูลที่รวบรวมไว้ที่เกี่ยวข้องกับการเรียกใช้ฟังก์ชัน โดยทั่วไปข้อมูลนี้รวมถึงอาร์กิวเมนต์ที่ส่งไปยังฟังก์ชัน th ตัวแปรโลคัลและตำแหน่งที่จะส่งคืนเมื่อยกเลิก บันทึกการเปิดใช้งานเป็นอีกชื่อหนึ่งของสแต็กเฟรม โครงร่างของเฟรมสแต็กถูกกำหนดใน ABI โดยผู้ผลิตและคอมไพเลอร์ทั้งหมดที่สนับสนุน ISA ต้องเป็นไปตามมาตรฐานนี้อย่างไรก็ตามโครงร่างโครงร่างสามารถพึ่งพาคอมไพเลอร์ได้ โดยทั่วไปขนาดเฟรมสแต็กไม่ จำกัด แต่มีแนวคิดที่เรียกว่า "โซนสีแดง / ป้องกัน" เพื่อให้การโทรของระบบ ... ฯลฯ ดำเนินการโดยไม่รบกวนเฟรมสแต็ก
มี SP เสมอ แต่สำหรับ ABIs บางตัว (ตัวอย่างเช่น ARM และ PowerPC) FP เป็นตัวเลือก อาร์กิวเมนต์ที่จำเป็นต้องวางลงบนสแต็กสามารถถูกตัดทิ้งโดยใช้ SP เท่านั้น ไม่ว่าเฟรมสแต็กจะถูกสร้างขึ้นสำหรับการเรียกใช้ฟังก์ชันหรือไม่นั้นขึ้นอยู่กับชนิดและจำนวนของอาร์กิวเมนต์ตัวแปรโลคัลและวิธีเข้าถึงตัวแปรโลคัลโดยทั่วไป บน ISAs ส่วนใหญ่อันดับแรกจะใช้การลงทะเบียนและหากมีข้อโต้แย้งมากกว่าการลงทะเบียนเพื่อส่งผ่านข้อโต้แย้งเหล่านี้จะถูกวางลงบนสแต็ก (ตัวอย่างเช่น x86 ABI มี 6 รีจิสเตอร์เพื่อส่งผ่านอาร์กิวเมนต์จำนวนเต็ม) ดังนั้นบางครั้งฟังก์ชั่นบางอย่างไม่จำเป็นต้องวางเฟรมสแต็กบนสแต็กเพียงแค่ที่อยู่ผู้ส่งถูกส่งไปยังสแต็ก