ทำไมหนังสือถึงพูดว่า“ คอมไพเลอร์จัดสรรพื้นที่สำหรับตัวแปรในหน่วยความจำ”


18

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

#include <iostream>
using namespace std;

int main()
{
   int foo;
   return 0;
}

และคอมไพล์มันและรับไฟล์ executable (ปล่อยให้มันเป็น program.exe) ตอนนี้ถ้าฉันรัน program.exe ไฟล์ที่ปฏิบัติการได้นี้จะสั่งให้จัดสรรพื้นที่สำหรับตัวแปร foo มันจะไม่? โปรดอธิบายว่าทำไมหนังสือพูดต่อไปว่า "ผู้รวบรวมจะทำสิ่งนี้ ... ทำอย่างนั้น"


11
คุณกำลังพูดถึงหนังสือเล่มไหน?
wirrbel

4
"คำถามที่เกี่ยวข้อง" ของคุณควรเป็นคำถามแยกต่างหาก
SShaheen


คอมไพเลอร์สร้างรหัสที่ทำสิ่งนี้หรือนั่นคือสิ่งที่พวกเขากำลังพูด ไม่ว่าโดยตรงหรือโดยอ้อม
old_timer

FYI stackoverflow.com/questions/7372024/…และโปรดทราบว่าคอมไพเลอร์อาจตัดสินใจเปลี่ยนตำแหน่งของตัวแปรที่รับรู้ในหน่วยความจำเพื่อประโยชน์ในการจัดตำแหน่งเช่น: stackoverflow.com/questions/17774276/ …
NoChance

คำตอบ:


20

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

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

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


ใช่นั่นคือสิ่งที่ฉันเชื่อ ขอบคุณสำหรับคำตอบด่วน!
ผู้ทำรหัสอย่างสันติ

12
คอมไพเลอร์จัดสรรสำหรับตัวแปร foo บนสแต็กโดยการแทนที่โดยอ็อฟเซ็ตไปยังตัวชี้สแต็กระหว่างการคอมไพล์ ไม่เกี่ยวข้องกับการจัดสรรฮีปทั้งหมดซึ่งดำเนินการโดยmallocet อัล
wirrbel

@holger: การคัดค้านของคุณถูกต้องทางเทคนิคแน่นอน แต่จะต้องจัดสรรพื้นที่สแต็กดังกล่าวเมื่อโปรแกรมเริ่มก่อนที่จะสามารถใช้งานได้ (ซึ่งอาจเกิดขึ้นได้หลายวิธีขึ้นอยู่กับสถาปัตยกรรมของ CPU) ฉันพยายามค้นหารายละเอียดว่าเกิดอะไรขึ้น แต่ไม่ประสบความสำเร็จมากนัก
thorsten müller

2
ฉันคิดว่าขนาดสแต็กสำหรับเธรดหลักถูกสงวนไว้โดยตัวลิงก์และจัดการโดยระบบปฏิบัติการ สำหรับเธรดที่กำหนดเองจะคล้ายกับการจัดสรรฮีปมากขึ้นเช่นผู้โทรสามารถแก้ไขขนาดตอนรันไทม์
wirrbel

4

มันขึ้นอยู่กับตัวแปร ระบบปฏิบัติการจัดสรรฮีปโปรแกรมจะจัดสรรสแต็กและคอมไพเลอร์จะจัดสรรพื้นที่สำหรับ globals / statics นั่นคือสร้างขึ้นใน exe เอง หากคุณจัดสรรหน่วยความจำระดับโลก 1MB ขนาด exe ของคุณจะเพิ่มขึ้นอย่างน้อย 1MB


1
นั่นไม่ใช่สิ่งที่คำถามนี้เกี่ยวกับ
Philipp

2
จริงๆแล้วมันใกล้กับคำถามมากกว่าคำตอบอื่น ๆ ที่แสดงไว้ที่นี่
wirrbel

@ James อ่านี่ไม่ใช่ประสบการณ์ของฉัน ตัวอย่างเช่นint test[256][1024]; int main(){ test[0][0]=2; return 0; } โปรแกรมขนาดเล็กนี้มีการจัดสรร 1MB แต่สร้างไฟล์วัตถุ 1.4 Kb และปฏิบัติการได้ 8.4 Kb ควรใช้ RAM ในปริมาณที่ถูกต้อง
Garet Claborn

1
ไม่ควรเป็นเพียงคำสั่งการจัดสรรที่เก็บไว้สำหรับ globals เท่านั้น หากคุณ hardcoded ค่าทั้งหมดโดยใช้ primitives เช่น int หรือ char ขนาดของ executable จะเพิ่มขึ้นอย่างแน่นอนมากกว่าจำนวนของตัวแปรที่เพิ่มเข้ามา เช่นint a1=1,a2=2,... ไปจนถึง ... , a1048576=1048576;เฉพาะคุณเท่านั้นที่จะได้รับบางสิ่งที่ใหญ่กว่า 1mb ฉันคิดว่า
Garet Claborn

2
มันคือสิ่งที่จะนำข้อมูลไปไว้ในส่วน BSS ของ exe
James

4

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

ตัวอย่างเช่นเมื่อคุณเขียน

int foo;

คุณสามารถดูได้ว่า 'ฉันบอกคอมไพเลอร์ถึง [ ในผลลัพธ์มันสร้าง ] คำขอให้คอมพิวเตอร์จองหน่วยความจำเพียงพอสำหรับ int ที่ฉันสามารถอ้างอิงได้ในภายหลังผู้รวบรวมอาจใช้ id ทรัพยากรหรือกลไกบางอย่างเพื่อติดตาม foo ใน รหัสเครื่องคุณจะได้ใช้ foo ในไฟล์ข้อความแทนการเขียนชุดประกอบ! ไชโย !

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


3

การพูดว่า "คอมไพเลอร์จัดสรรหน่วยความจำ" อาจไม่ถูกต้องตามข้อเท็จจริงในความหมายตามตัวอักษร แต่มันเป็นคำอุปมาที่ชี้นำในทางที่ถูกต้อง

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

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

แต่มันก็สมเหตุสมผลที่จะคิดโปรแกรมและคอมไพเลอร์และซีพียูในฐานะคนตัวเล็กที่อาศัยอยู่ในคอมพิวเตอร์ไม่ใช่เพราะมันเป็นจริง แต่เพราะนั่นเป็นคำอุปมาที่เหมาะกับสมองมนุษย์

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


0

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

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

byte* pointer = (byte*)malloc(...);

ในรันไทม์ malloc อาจส่งคืนหมายเลขที่กำหนดเอง แต่คอมไพเลอร์ไม่สนใจสิ่งที่มันสนใจคือสถานที่เก็บหมายเลขนั้น


0

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

ในสภาพแวดล้อม C-ish จะมีพื้นที่สามประเภทสำหรับตัวแปร: -

  • บล็อกคงที่สำหรับตัวแปรคงที่
  • บล็อกขนาดใหญ่สำหรับตัวแปร "อัตโนมัติ" มักจะเรียกว่า "สแต็ค" ฟังก์ชั่นคว้าชิ้นบนรายการและปล่อยมันกลับมา
  • บล็อกขนาดใหญ่ที่เรียกว่า "ฮีป" ซึ่งเป็นที่ที่จัดสรรหน่วยความจำที่มีการจัดการโปรแกรมจาก (ใช้ malloc () หรือ API การจัดการหน่วยความจำที่คล้ายกัน

ในหน่วยความจำฮีประบบปฏิบัติการที่ทันสมัยจะไม่ถูกสงวนไว้จริง ๆ แต่ถูกจัดสรรตามความจำเป็น


0

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

(ถ้าคุณอยากรู้ว่าตัวแปรของคุณอยู่ที่ไหนคุณสามารถตรวจสอบได้ว่ามันสกปรก (ถ้าคุณไม่ต้องการตรวจสอบโครงสร้างของไฟล์ obj แล้วทำไมล่ะ?) ดังนั้นคุณสามารถประกาศตัวแปรที่แตกต่างกัน: คงที่ สแตติกไดนามิก - malloc()จัดสรร ฯลฯ และแสดงที่อยู่ (ใช้ตัว%Xจัดรูปแบบprintf()เพื่อให้อ่านง่ายขึ้น) ตัวแปรที่อยู่ในสแต็กจะมีที่อยู่หน่วยความจำที่แตกต่างกันมาก)


0

สิ่งเดียวที่ทำที่รันไทม์จะกระแทกพอยน์เตอร์สแต็คตามจำนวนที่แน่นอน ดังนั้นคอมไพเลอร์ตัดสินใจล่วงหน้า:

  • ฟังก์ชันสแต็กจำเป็นต้องใช้พื้นที่สแต็กเท่าใด
  • สิ่งที่ชดเชยจากตัวชี้สแต็คทุกตัวแปรแต่ละคนจะอยู่

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

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