สแต็กเติบโตขึ้นหรือลง?


90

ฉันมีรหัสชิ้นนี้ใน c:

ผลลัพธ์คือ:

ดังนั้นฉันเห็นว่าจากaถึงa[2]ที่อยู่หน่วยความจำจะเพิ่มขึ้นทีละ 4 ไบต์ แต่จากqถึงsที่อยู่หน่วยความจำจะลดลง 4 ไบต์

ฉันสงสัย 2 อย่าง:

  1. สแต็กเติบโตขึ้นหรือลง? (ดูเหมือนทั้งกับฉันในกรณีนี้)
  2. เกิดอะไรขึ้นระหว่างa[2]และqที่อยู่หน่วยความจำ? เหตุใดจึงมีความทรงจำที่แตกต่างกันมาก (20 ไบต์)

หมายเหตุ: นี่ไม่ใช่คำถามการบ้าน ฉันอยากรู้ว่าสแต็กทำงานอย่างไร ขอบคุณสำหรับความช่วยเหลือ


การสั่งซื้อเป็นไปโดยพลการ ช่องว่างอาจจะเก็บผลลัพธ์ระดับกลางเช่น & q หรือ & s - ดูที่การถอดชิ้นส่วนและดูด้วยตัวคุณเอง
Tom Leys

ฉันยอมรับอ่านรหัสการประกอบ หากคุณกำลังถามคำถามประเภทนี้ก็ถึงเวลาเรียนรู้ที่จะอ่านมัน
Per Johansson

คำตอบเวอร์ชันประกอบที่ง่ายกว่า: stackoverflow.com/questions/664744/…
Ciro Santilli 郝海东冠状病六四事件法轮功

คำตอบ:


74

พฤติกรรมของสแต็ก (เติบโตขึ้นหรือเติบโตลง) ขึ้นอยู่กับไบนารีอินเทอร์เฟซของแอปพลิเคชัน (ABI) และวิธีจัดระเบียบ call stack (aka activation record)

ตลอดอายุการใช้งานโปรแกรมจะต้องสื่อสารกับโปรแกรมอื่น ๆ เช่น OS ABI กำหนดว่าโปรแกรมสามารถสื่อสารกับโปรแกรมอื่นได้อย่างไร

สแต็กสำหรับสถาปัตยกรรมที่แตกต่างกันสามารถเติบโตได้ทั้งสองวิธี แต่สำหรับสถาปัตยกรรมนั้นจะสอดคล้องกัน กรุณาตรวจสอบนี้เชื่อมโยงวิกิพีเดีย แต่การเติบโตของสแต็กจะถูกกำหนดโดย ABI ของสถาปัตยกรรมนั้น

ตัวอย่างเช่นหากคุณใช้ MIPS ABI call stack จะถูกกำหนดดังต่อไปนี้

ให้เราพิจารณาว่าฟังก์ชัน 'fn1' เรียก 'fn2' ตอนนี้สแต็กเฟรมที่เห็นโดย 'fn2' เป็นดังนี้:

ตอนนี้คุณสามารถเห็นสแต็กเติบโตลดลง ดังนั้นหากตัวแปรถูกจัดสรรให้กับเฟรมภายในของฟังก์ชันแอดเดรสของตัวแปรจะลดลงอย่างแท้จริง คอมไพเลอร์สามารถตัดสินใจเกี่ยวกับลำดับของตัวแปรสำหรับการจัดสรรหน่วยความจำ (ในกรณีของคุณอาจเป็น 'q' หรือ 's' ที่ได้รับการจัดสรรหน่วยความจำสแต็กก่อน แต่โดยทั่วไปคอมไพลเลอร์จะจัดสรรหน่วยความจำสแตกตามลำดับของการประกาศตัวแปร)

แต่ในกรณีของอาร์เรย์การจัดสรรจะมีตัวชี้เพียงตัวเดียวและต้องมีการจัดสรรหน่วยความจำจะชี้โดยตัวชี้เดียว หน่วยความจำต้องอยู่ติดกันสำหรับอาร์เรย์ ดังนั้นแม้ว่าสแต็กจะลดลง แต่สำหรับอาร์เรย์ที่สแต็กจะเติบโตขึ้น


5
นอกจากนี้หากคุณต้องการตรวจสอบว่าสแต็กเติบโตขึ้นหรือลง ประกาศตัวแปรท้องถิ่นในฟังก์ชันหลัก พิมพ์ที่อยู่ของตัวแปร เรียกใช้ฟังก์ชันอื่นจาก main ประกาศตัวแปรท้องถิ่นในฟังก์ชัน พิมพ์ที่อยู่ จากที่อยู่ที่พิมพ์เราสามารถพูดได้ว่าสแต็กเติบโตขึ้นหรือลง
พระพิฆเนศ Gopalasubramanian

ขอบคุณพระพิฆเนศฉันมีคำถามเล็กน้อย: ในรูปที่คุณวาดในบล็อกที่สามคุณหมายถึง "calleR บันทึกลงทะเบียนที่ใช้ใน CALLER" หรือไม่เพราะเมื่อ f1 เรียก f2 เราต้องเก็บที่อยู่ f1 ไว้ สำหรับ f2) และ f1 (calleR) ไม่ได้ลงทะเบียน f2 (callee) ขวา?
CSawy

43

นี่เป็นคำถามสองข้อ หนึ่งคือวิธีที่สแต็กเติบโตขึ้นเมื่อฟังก์ชันหนึ่งเรียกใช้อีกฟังก์ชันหนึ่ง (เมื่อมีการจัดสรรเฟรมใหม่) และอีกอันเกี่ยวกับการจัดวางตัวแปรในเฟรมของฟังก์ชันหนึ่ง ๆ

มาตรฐาน C ไม่ได้ระบุไว้ แต่คำตอบแตกต่างกันเล็กน้อย:

  • สแต็กจะเติบโตไปทางใดเมื่อมีการจัดสรรเฟรมใหม่ - ถ้าฟังก์ชัน f () เรียกใช้ฟังก์ชัน g () fตัวชี้เฟรมจะมากกว่าหรือน้อยกว่าgตัวชี้เฟรม สิ่งนี้สามารถไปได้ทางใดทางหนึ่ง - ขึ้นอยู่กับคอมไพเลอร์และสถาปัตยกรรมเฉพาะ (ค้นหา "การเรียกแบบการประชุม") แต่จะสอดคล้องกันเสมอภายในแพลตฟอร์มที่กำหนด (มีข้อยกเว้นแปลก ๆ เล็กน้อยดูความคิดเห็น) ขาลงเป็นเรื่องปกติมากขึ้น เป็นกรณีใน x86, PowerPC, MIPS, SPARC, EE และ Cell SPU
  • ตัวแปรโลคัลของฟังก์ชันถูกจัดวางภายในเฟรมสแต็กอย่างไร สิ่งนี้ไม่ระบุและไม่สามารถคาดเดาได้อย่างสมบูรณ์ คอมไพเลอร์มีอิสระในการจัดเรียงตัวแปรภายในอย่างไรก็ตามต้องการให้ได้ผลลัพธ์ที่มีประสิทธิภาพสูงสุด

7
"สอดคล้องกันเสมอภายในแพลตฟอร์มที่กำหนด" - ไม่รับประกัน ฉันเคยเห็นแพลตฟอร์มที่ไม่มีหน่วยความจำเสมือนซึ่งมีการขยายสแต็กแบบไดนามิก บล็อกสแต็กใหม่มีผลบังคับใช้ malloced ซึ่งหมายความว่าคุณจะ "ลง" หนึ่งบล็อกสแต็กชั่วขณะจากนั้น "ไปด้านข้าง" ไปยังบล็อกอื่น "ด้านข้าง" อาจหมายถึงที่อยู่ที่มากขึ้นหรือน้อยลงซึ่งขึ้นอยู่กับโชคของการจับ
Steve Jessop

2
สำหรับรายละเอียดเพิ่มเติมของข้อ 2 - คอมไพเลอร์อาจสามารถตัดสินใจได้ว่าตัวแปรไม่จำเป็นต้องอยู่ในหน่วยความจำ (เก็บไว้ในทะเบียนสำหรับอายุของตัวแปร) และ / หรือหากอายุการใช้งานของตัวแปรสองตัวขึ้นไปไม่ ' t ทับซ้อนกันคอมไพลเลอร์อาจตัดสินใจใช้หน่วยความจำเดียวกันสำหรับตัวแปรมากกว่าหนึ่งตัว
Michael Burr

2
ฉันคิดว่า S / 390 (IBM zSeries) มี ABI ที่มีการเชื่อมโยงเฟรมการโทรแทนที่จะเติบโตบนสแต็ก
ephemient

2
ถูกต้องใน S / 390 การโทรคือ "BALR" สาขาและการลงทะเบียนลิงค์ ค่าที่ส่งคืนจะถูกใส่ลงในรีจิสเตอร์แทนที่จะผลักลงในสแต็ก ฟังก์ชันส่งคืนเป็นสาขาไปยังเนื้อหาของรีจิสเตอร์นั้น เมื่อสแต็กมีความลึกมากขึ้นพื้นที่ว่างจะถูกจัดสรรในฮีปและจะถูกผูกติดกัน นี่คือที่ที่ MVS ที่เทียบเท่ากับ "/ bin / true" ได้รับชื่อ: "IEFBR14" เวอร์ชันแรกมีคำสั่งเดียว: "BR 14" ซึ่งแตกแขนงไปยังเนื้อหาของ register 14 ซึ่งมีที่อยู่สำหรับส่งคืน
janm

1
และคอมไพเลอร์บางตัวในโปรเซสเซอร์ PIC ทำการวิเคราะห์โปรแกรมทั้งหมดและจัดสรรตำแหน่งคงที่สำหรับตัวแปรอัตโนมัติของแต่ละฟังก์ชัน สแต็กจริงมีขนาดเล็กและไม่สามารถเข้าถึงได้จากซอฟต์แวร์ เป็นที่อยู่สำหรับส่งคืนเท่านั้น
janm

13

ทิศทางที่สแต็กเติบโตเป็นสถาปัตยกรรมเฉพาะ ที่กล่าวว่าความเข้าใจของฉันคือสถาปัตยกรรมฮาร์ดแวร์เพียงไม่กี่ชิ้นเท่านั้นที่มีสแต็กที่เติบโต

ทิศทางที่สแต็กเติบโตขึ้นนั้นไม่ขึ้นอยู่กับโครงร่างของวัตถุแต่ละชิ้น ดังนั้นในขณะที่สแต็กอาจขยายตัวลงอาร์เรย์จะไม่ (กล่าวคือ & array [n] จะเป็น <& array [n + 1]);


4

ไม่มีสิ่งใดในมาตรฐานที่กำหนดวิธีการจัดระเบียบสิ่งต่างๆบนสแต็กเลย ในความเป็นจริงคุณสามารถสร้างคอมไพเลอร์ที่สอดคล้องกันซึ่งไม่ได้เก็บองค์ประกอบอาร์เรย์ไว้ที่องค์ประกอบที่อยู่ติดกันบนสแต็กเลยหากมีความชาญฉลาดในการคำนวณองค์ประกอบอาร์เรย์อย่างถูกต้อง (เพื่อให้รู้ว่า1คือ 1K ห่างจาก [0] และสามารถปรับได้)

เหตุผลที่คุณอาจได้รับผลลัพธ์ที่แตกต่างกันเนื่องจากในขณะที่สแต็กอาจขยายตัวลงเพื่อเพิ่ม "วัตถุ" เข้าไปอาร์เรย์นั้นเป็น "วัตถุ" เดียวและอาจมีองค์ประกอบอาร์เรย์จากน้อยไปหามากในลำดับที่ตรงกันข้าม แต่ไม่ปลอดภัยที่จะพึ่งพาพฤติกรรมดังกล่าวเนื่องจากทิศทางสามารถเปลี่ยนแปลงได้และตัวแปรสามารถสลับไปมาได้ด้วยเหตุผลหลายประการรวมถึง แต่ไม่ จำกัด เพียง:

  • การเพิ่มประสิทธิภาพ
  • การจัดตำแหน่ง
  • ความต้องการของบุคคลที่เป็นส่วนจัดการสแต็กของคอมไพเลอร์

ดูที่นี่สำหรับบทความที่ดีเยี่ยมของฉันในทิศทางสแต็ค :-)

เพื่อตอบคำถามเฉพาะของคุณ:

  1. สแต็กเติบโตขึ้นหรือลง?
    มันไม่สำคัญเลย (ในแง่ของมาตรฐาน) แต่เนื่องจากคุณถามมันสามารถเติบโตขึ้นหรือลงในหน่วยความจำขึ้นอยู่กับการใช้งาน
  2. เกิดอะไรขึ้นระหว่างที่อยู่หน่วยความจำ [2] และ q เหตุใดจึงมีความทรงจำที่แตกต่างกันมาก (20 ไบต์)?
    มันไม่สำคัญเลย (ในแง่ของมาตรฐาน) ดูเหตุผลที่เป็นไปได้ด้านบน

ฉันเห็นคุณเชื่อมโยงว่าสถาปัตยกรรม CPU ส่วนใหญ่ใช้วิธี "ขยายตัว" คุณรู้หรือไม่ว่าการทำเช่นนั้นมีประโยชน์อย่างไร
บาย

ไม่มีความคิดจริงๆ เป็นไปได้ว่ามีคนคิดว่าโค้ดขึ้นไปจาก 0 ดังนั้นสแต็กควรลงจาก highmem เพื่อลดความเป็นไปได้ที่จะตัดกัน แต่ CPU บางตัวเริ่มรันโค้ดโดยเฉพาะในตำแหน่งที่ไม่ใช่ศูนย์ดังนั้นอาจไม่เป็นเช่นนั้น เช่นเดียวกับสิ่งต่างๆส่วนใหญ่อาจจะทำแบบนั้นเพียงเพราะเป็นวิธีแรกที่ใครบางคนคิดจะทำ :-)
paxdiablo

@lzprgmr: มีข้อดีเล็กน้อยในการจัดสรรฮีปบางประเภทตามลำดับจากน้อยไปหามากและในอดีตเป็นเรื่องปกติที่สแต็กและฮีปจะนั่งที่ปลายอีกด้านของพื้นที่แอดเดรสทั่วไป หากการใช้งานสแต็ก + ฮีป + สแต็กรวมกันไม่เกินหน่วยความจำที่มีอยู่จึงไม่ต้องกังวลว่าโปรแกรมจะใช้หน่วยความจำสแต็กเท่าใด
supercat

3

บน x86 หน่วยความจำ "การจัดสรร" ของสแต็กเฟรมประกอบด้วยการลบจำนวนไบต์ที่จำเป็นออกจากตัวชี้สแต็ก (ฉันเชื่อว่าสถาปัตยกรรมอื่น ๆ ก็คล้ายกัน) ในแง่นี้ฉันเดาว่าสแต็กคำราม "ลง" เนื่องจากที่อยู่จะเล็กลงเรื่อย ๆ เมื่อคุณเรียกลึกเข้าไปในสแต็กมากขึ้น (แต่ฉันมักจะจินตนาการถึงหน่วยความจำโดยเริ่มต้นด้วย 0 ที่ด้านซ้ายบนและได้รับแอดเดรสที่ใหญ่ขึ้นเมื่อคุณย้าย ไปทางขวาและปิดลงดังนั้นในภาพจิตของฉันสแต็คจึงเติบโตขึ้น ... ) ลำดับของตัวแปรที่ประกาศอาจไม่มีผลต่อที่อยู่ของพวกเขา - ฉันเชื่อว่ามาตรฐานอนุญาตให้คอมไพเลอร์จัดลำดับใหม่ได้ตราบเท่าที่ไม่ก่อให้เกิดผลข้างเคียง (โปรดแก้ไขฉันหากฉันผิด) . พวกเขา '

ช่องว่างรอบอาร์เรย์อาจเป็นช่องว่างบางอย่าง แต่ก็ลึกลับสำหรับฉัน


1
อันที่จริงฉันรู้ว่าคอมไพเลอร์สามารถเรียงลำดับใหม่ได้เพราะมันเป็นอิสระที่จะไม่จัดสรรให้เลย สามารถใส่ลงในรีจิสเตอร์และไม่ใช้พื้นที่สแต็กใด ๆ
rmeador

ไม่สามารถใส่ลงในทะเบียนได้หากคุณอ้างอิงที่อยู่
florin

จุดดีไม่ได้พิจารณาอย่างนั้น แต่ก็ยังพอเป็นหลักฐานได้ว่าคอมไพเลอร์สามารถจัดลำดับใหม่ได้เนื่องจากเรารู้ว่ามันสามารถทำได้อย่างน้อยก็ในช่วงเวลาหนึ่ง :)
rmeador

1

ก่อนอื่นพื้นที่ 8 ไบต์ที่ไม่ได้ใช้ในหน่วยความจำ (ไม่ใช่ 12 จำสแต็กจะลดลงดังนั้นพื้นที่ที่ไม่ได้รับการจัดสรรคือจาก 604 ถึง 597) และทำไม?. เนื่องจากข้อมูลทุกประเภทใช้พื้นที่ในหน่วยความจำโดยเริ่มจากแอดเดรสหารด้วยขนาด ในกรณีอาร์เรย์ของจำนวนเต็ม 3 จำนวนใช้พื้นที่หน่วยความจำ 12 ไบต์และ 604 หารด้วย 12 ไม่ได้ดังนั้นจึงเว้นช่องว่างไว้จนกว่าจะพบแอดเดรสหน่วยความจำซึ่งหารด้วย 12 ได้เท่ากับ 596

ดังนั้นพื้นที่หน่วยความจำที่จัดสรรให้กับอาร์เรย์จึงอยู่ระหว่าง 596 ถึง 584 แต่เนื่องจากการจัดสรรอาร์เรย์เป็นไปอย่างต่อเนื่องดังนั้นองค์ประกอบแรกของอาร์เรย์จึงเริ่มต้นจาก 584 แอดเดรสไม่ใช่จาก 596


1

คอมไพเลอร์มีอิสระในการจัดสรรตัวแปรภายใน (อัตโนมัติ) ณ ที่ใด ๆ บนเฟรมสแต็กในเครื่องคุณไม่สามารถสรุปทิศทางการเติบโตของสแต็กได้อย่างน่าเชื่อถือจากสิ่งนั้น คุณสามารถอนุมานทิศทางการเติบโตของสแต็กได้จากการเปรียบเทียบที่อยู่ของเฟรมสแต็กที่ซ้อนกันนั่นคือการเปรียบเทียบที่อยู่ของตัวแปรโลคัลภายในสแต็กเฟรมของฟังก์ชันเทียบกับแคลลี:


5
ฉันค่อนข้างแน่ใจว่าเป็นพฤติกรรมที่ไม่ได้กำหนดไว้ในการลบพอยน์เตอร์ไปยังออบเจ็กต์สแต็กที่แตกต่างกัน - พอยน์เตอร์ที่ไม่ได้เป็นส่วนหนึ่งของอ็อบเจกต์เดียวกันนั้นเทียบไม่ได้ เห็นได้ชัดว่ามันจะไม่ขัดข้องกับสถาปัตยกรรม "ปกติ" ใด ๆ
Steve Jessop

@SteveJessop มีวิธีใดบ้างที่เราสามารถแก้ไขเพื่อให้ได้ทิศทางของ stack โดยทางโปรแกรม?
xxks-kkk

@ xxks-kkk: โดยหลักการแล้วไม่เนื่องจากการใช้งาน C ไม่จำเป็นต้องมี "ทิศทางของสแต็ก" ตัวอย่างเช่นจะไม่ละเมิดมาตรฐานที่จะมีรูปแบบการเรียกที่มีการจัดสรรบล็อกสแต็กไว้ด้านหน้าจากนั้นรูทีนการจัดสรรหน่วยความจำภายในแบบสุ่มหลอกจะถูกใช้เพื่อกระโดดไปรอบ ๆ ภายใน ในทางปฏิบัติมันใช้งานได้จริงตามที่ Matja อธิบาย
Steve Jessop

0

ฉันไม่คิดว่ามันจะเป็นแบบนั้น อาร์เรย์ดูเหมือนจะ "เติบโต" เนื่องจากหน่วยความจำนั้นควรได้รับการจัดสรรอย่างต่อเนื่อง อย่างไรก็ตามเนื่องจาก q และ s ไม่เกี่ยวข้องกันเลยคอมไพเลอร์จึงติดแต่ละหน่วยความจำไว้ในตำแหน่งหน่วยความจำที่ว่างโดยพลการภายในสแต็กซึ่งอาจเป็นขนาดที่พอดีกับขนาดจำนวนเต็มดีที่สุด

สิ่งที่เกิดขึ้นระหว่าง [2] และ q คือช่องว่างรอบตำแหน่งของ q ไม่ใหญ่พอ (กล่าวคือไม่ใหญ่กว่า 12 ไบต์) เพื่อจัดสรรอาร์เรย์จำนวนเต็ม 3 ตัว


ถ้าเป็นเช่นนั้นทำไม q, s ถึงไม่มีหน่วยความจำที่อาจเกิดขึ้น? (เช่นที่อยู่ของ q: 2293612 ที่อยู่ของ s: 2293608 ที่อยู่ของ a: 2293604)

ฉันเห็น "ช่องว่าง" ระหว่าง s และ a

เนื่องจาก s และ a ไม่ได้รับการจัดสรรร่วมกัน - พอยน์เตอร์เพียงตัวเดียวที่ต้องอยู่ติดกันคือตัวชี้ในอาร์เรย์ หน่วยความจำอื่นสามารถจัดสรรได้ทุกที่
javanix

0

สแต็กของฉันดูเหมือนจะขยายไปยังที่อยู่ที่มีหมายเลขต่ำกว่า

คอมพิวเตอร์เครื่องอื่นอาจแตกต่างกันหรือแม้แต่ในคอมพิวเตอร์ของฉันเองถ้าฉันใช้การเรียกใช้คอมไพเลอร์ ... หรือคอมไพเลอร์ muigt เลือกที่จะไม่ใช้สแต็กเลย (อินไลน์ทุกอย่าง (ฟังก์ชันและตัวแปรถ้าฉันไม่ได้ใช้ที่อยู่ของพวกเขา))

$ / usr / bin / gcc -Wall -Wextra -std = c89 -pedantic stack.c
$ ./a.out
ระดับ 4: x อยู่ที่ 0x7fff7781190c
ระดับ 3: x อยู่ที่ 0x7fff778118ec
ระดับ 2: x อยู่ที่ 0x7fff778118cc
ระดับ 1: x อยู่ที่ 0x7fff778118ac
ระดับ 0: x อยู่ที่ 0x7fff7781188c

0

สแต็กเติบโตลง (บน x86) อย่างไรก็ตามสแต็กจะถูกจัดสรรในบล็อกเดียวเมื่อฟังก์ชันโหลดขึ้นและคุณไม่มีการรับประกันว่าไอเท็มจะอยู่ในสแต็กลำดับใด

ในกรณีนี้จะจัดสรรพื้นที่สำหรับสอง ints และอาร์เรย์สาม int บนสแต็ก นอกจากนี้ยังจัดสรรอีก 12 ไบต์เพิ่มเติมหลังจากอาร์เรย์ดังนั้นจึงมีลักษณะดังนี้:


ช่องว่างภายใน [12 ไบต์] (?) [12 ไบต์]
s [4 ไบต์]
q [4 ไบต์]

ไม่ว่าด้วยเหตุผลใดคอมไพเลอร์ของคุณจึงตัดสินใจว่าจำเป็นต้องจัดสรร 32 ไบต์สำหรับฟังก์ชันนี้และอาจมากกว่านั้น คุณเป็นโปรแกรมเมอร์ C คุณไม่เข้าใจว่าทำไม

ถ้าคุณอยากรู้ว่าทำไมคอมไพล์โค้ดเป็นภาษาแอสเซมบลีฉันเชื่อว่ามันเป็น -S บน gcc และ / S บนคอมไพเลอร์ C ของ MS หากคุณดูคำแนะนำในการเปิดฟังก์ชันนั้นคุณจะเห็นตัวชี้สแต็กเก่าถูกบันทึกและลบ 32 (หรืออย่างอื่น!) ออกจากฟังก์ชันนั้น จากตรงนั้นคุณสามารถดูว่าโค้ดเข้าถึงบล็อกหน่วยความจำ 32 ไบต์นั้นได้อย่างไรและดูว่าคอมไพเลอร์ของคุณกำลังทำอะไรอยู่ ในตอนท้ายของฟังก์ชันคุณจะเห็นตัวชี้สแต็กถูกเรียกคืน


0

ขึ้นอยู่กับระบบปฏิบัติการและคอมไพเลอร์ของคุณ


ไม่รู้ว่าทำไมคำตอบของฉันถึงถูกโหวตไม่ลง มันขึ้นอยู่กับระบบปฏิบัติการและคอมไพเลอร์ของคุณจริงๆ ในบางระบบสแต็กจะลดลง แต่ในระบบอื่น ๆ จะเติบโตขึ้น และในบางระบบจะไม่มีสแต็กเฟรมแบบกดลงจริง แต่เป็นการจำลองด้วยพื้นที่สำรองของหน่วยความจำหรือชุดรีจิสเตอร์
David R Tribble

3
อาจเป็นเพราะการยืนยันด้วยประโยคเดียวไม่ใช่คำตอบที่ดี
Lightness Races ใน Orbit

0

สแต็คเติบโตลง ดังนั้น f (g (h ())) สแต็กที่จัดสรรสำหรับ h จะเริ่มต้นที่ที่อยู่ต่ำกว่าจากนั้น g และ g จะต่ำกว่าตามด้วย f แต่ตัวแปรภายในสแตกต้องเป็นไปตามข้อกำหนด C

http://c0x.coding-guidelines.com/6.5.8.html

1206 ถ้าออบเจ็กต์ที่ชี้ไปเป็นสมาชิกของอ็อบเจ็กต์การรวมเดียวกันตัวชี้ไปยังสมาชิกโครงสร้างที่ประกาศในภายหลังจะเปรียบเทียบมากกว่าพอยน์เตอร์ถึงสมาชิกที่ประกาศไว้ก่อนหน้านี้ในโครงสร้างและพอยน์เตอร์ไปยังองค์ประกอบอาร์เรย์ที่มีค่าตัวห้อยมากกว่าจะเปรียบเทียบมากกว่าพอยน์เตอร์กับองค์ประกอบที่เหมือนกัน อาร์เรย์ที่มีค่าตัวห้อยต่ำกว่า

& a [0] <& a [1] ต้องเป็นจริงเสมอไม่ว่าจะจัดสรร "a" อย่างไร


ในเครื่องจักรส่วนใหญ่สแต็กจะลดลง - ยกเว้นเครื่องที่เติบโตขึ้น
Jonathan Leffler

0

เติบโตลงและนี่เป็นเพราะมาตรฐานคำสั่ง endian byte เล็กน้อยเมื่อพูดถึงชุดข้อมูลในหน่วยความจำ

วิธีหนึ่งที่คุณสามารถดูได้ก็คือสแต็กจะเติบโตขึ้นด้านบนถ้าคุณดูหน่วยความจำจาก 0 จากด้านบนและสูงสุดจากด้านล่าง

สาเหตุที่ทำให้สแต็กเติบโตลดลงคือสามารถหักล้างจากมุมมองของสแต็กหรือตัวชี้ฐานได้

โปรดจำไว้ว่าการยกเลิกการอ้างอิงประเภทใด ๆ จะเพิ่มขึ้นจากที่อยู่ต่ำสุดไปสูงสุด เนื่องจาก Stack ขยายตัวลง (ที่อยู่สูงสุดไปต่ำสุด) จึงช่วยให้คุณปฏิบัติกับสแต็กเหมือนหน่วยความจำแบบไดนามิก

นี่เป็นสาเหตุหนึ่งที่ทำให้การเขียนโปรแกรมและภาษาสคริปต์จำนวนมากใช้เครื่องเสมือนแบบสแต็กแทนที่จะใช้การลงทะเบียน


The reason for the stack growing downward is to be able to dereference from the perspective of the stack or base pointer.เหตุผลที่ดีมาก
user3405291

0

มันขึ้นอยู่กับสถาปัตยกรรม ในการตรวจสอบระบบของคุณเองให้ใช้รหัสนี้จากGeeksForGeeks :

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.