ภาษารวบรวมและตีความ


284

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

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


32
คุณเลือกภาษาที่เลวร้ายที่สุดสำหรับการเปรียบเทียบนี้ ทั้งสองเป็นคอมโพสิต ความแตกต่างที่แท้จริงระหว่างพวกเขาคือ JITer และแม้แต่ Python ก็มีบางส่วน (psyco)
Ignacio Vazquez-Abrams

1
ตัวอย่างที่ดีของภาษาที่คอมไพล์แบบอินเตอร์แอคทีฟคือ Clojure - ทุกอย่างถูกคอมไพล์อย่างสมบูรณ์ (ก่อนจาก JVM จากนั้นไปที่โค้ดเนทีฟผ่าน JIT) อย่างไรก็ตามการรวบรวมซ้ำจำนวนมากเกิดขึ้นแบบไดนามิกและการพัฒนามักจะทำในเชลล์ REPL แบบโต้ตอบซึ่งคุณสามารถประเมินฟังก์ชันใด ๆ ที่คุณต้องการในสภาพแวดล้อมการทำงาน
mikera

Standard ML เป็นอีกภาษาที่คอมไพล์ด้วยการโต้ตอบ; คอมไพเลอร์ในตัวจะออกรหัสเครื่องจริงดั้งเดิมด้วย
Donal Fellows


คำตอบ:


460

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

ภาษาที่ถูกตีความเป็นภาษาที่คำสั่งไม่ได้ดำเนินการโดยตรงโดยเครื่องเป้าหมาย แต่แทนที่จะอ่านและดำเนินการโดยโปรแกรมอื่น ๆ (ซึ่งโดยปกติจะเขียนด้วยภาษาของเครื่องดั้งเดิม) ตัวอย่างเช่นการดำเนินการ "+" เดียวกันจะได้รับการยอมรับโดยล่าม ณ รันไทม์ซึ่งจะเรียกฟังก์ชัน "add (a, b)" ของตัวเองพร้อมกับอาร์กิวเมนต์ที่เหมาะสมซึ่งจะดำเนินการคำสั่ง "ADD" ของรหัสเครื่อง .

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

ฉันจะพูดคุยอย่างสมบูรณ์ (ปรมาจารย์ยกโทษให้ฉัน!) แต่โดยทั่ว ๆ ไปนี่คือข้อดีของภาษาที่รวบรวม:

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

และนี่คือข้อดีของภาษาที่ตีความ:

  • ใช้งานง่ายกว่า (การเขียนคอมไพเลอร์ที่ดีนั้นยากมาก !!)
  • ไม่จำเป็นต้องเรียกใช้ขั้นตอนการรวบรวม: สามารถรันโค้ดโดยตรง "ในทันที"
  • สามารถใช้ภาษาไดนามิกได้สะดวกกว่า

โปรดทราบว่าเทคนิคที่ทันสมัยเช่นการคอมไพล์ bytecode เพิ่มความซับซ้อนพิเศษ - สิ่งที่เกิดขึ้นที่นี่คือคอมไพเลอร์มีเป้าหมาย "เครื่องเสมือน" ซึ่งไม่เหมือนกับฮาร์ดแวร์พื้นฐาน คำแนะนำเครื่องเสมือนเหล่านี้สามารถรวบรวมได้อีกครั้งในภายหลังเพื่อรับรหัสเนทีฟ (เช่นที่ทำโดยคอมไพเลอร์ Java JVM JIT)


1
ภาษาที่รวบรวมไว้ทั้งหมดไม่จำเป็นต้องมีขั้นตอนการรวบรวมที่ช้า การใช้งาน Lisp ทั่วไปที่จริงจังนั้นเป็นคอมไพเลอร์และบ่อยครั้งที่พวกเขาไม่ได้กังวลกับล่าม ในทางตรงกันข้าม Java ไม่จำเป็นต้องมีขั้นตอนการรวบรวมและมันมักจะมองเห็นได้
David Thornley

2
@Kareem: คอมไพเลอร์ JIT ทำเพียง 1) และ 2) เพียงครั้งเดียว - หลังจากนั้นมันเป็นโค้ดเนทีฟตลอดทาง ล่ามต้องทำทั้ง 1) และ 2) ทุกครั้งที่มีการเรียกใช้โค้ด (ซึ่งอาจมีหลายครั้งหลายครา ... ) ดังนั้นเมื่อเวลาผ่านไปคอมไพเลอร์ของ JIT ชนะโดยระยะขอบยาว
mikera

3
ใช่ bytecode ถูกแปลเป็นรหัสเครื่องในบางช่วงระหว่างการเรียกใช้โปรแกรมโดยรวม (เมื่อเทียบกับก่อนหน้าการเรียกใช้งานโปรแกรม แต่โค้ดที่ระบุอาจถูกเรียกใช้งาน 10 ล้านครั้งขึ้นไปในระหว่างการเรียกใช้โปรแกรมโดยรวม มันอาจจะได้รับการรวบรวมเพียงครั้งเดียวจากไบต์รหัสไปยังเครื่อง ดังนั้นโอเวอร์เฮดแบบรันไทม์ของ JIT จึงมีขนาดเล็กและสามารถละเว้นได้สำหรับโปรแกรมที่รันนาน หลังจากคอมไพเลอร์ JIT ทำงานเสร็จแล้วคุณจะรันโค้ดเครื่องที่บริสุทธิ์ได้อย่างมีประสิทธิภาพตลอดทาง
mikera

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

2
@ mmachenry ไม่ใช่การแบ่งขั้วที่ผิดพลาด "การเขียนโปรแกรมภาษา" รวมทั้งการออกแบบและการดำเนิน ในขณะที่ในแง่ทฤษฎีความหมายภาษาให้สามารถทั้งรวบรวมและตีความในทางปฏิบัติโลกแห่งความจริงมีความแตกต่างอย่างมากในการดำเนินงาน ยังไม่มีใครแก้ไขวิธีการคอมไพล์ภาษาบางอย่างได้อย่างมีประสิทธิภาพ - มันเป็นปัญหาการวิจัยแบบเปิด
mikera

99

ภาษาเองไม่ได้แปลหรือแปลเฉพาะการใช้ภาษาเฉพาะ Java เป็นตัวอย่างที่สมบูรณ์แบบ มีแพลตฟอร์มแบบอิงไบต์ (JVM), คอมไพเลอร์เนทีฟ (gcj) และ interpeter สำหรับชุดของ Java (bsh) ดังนั้น Java ตอนนี้คืออะไร? Bytecode รวบรวมเรียบเรียงพื้นเมืองหรือตีความ?

ภาษาอื่น ๆ ที่รวบรวมและตีความคือ Scala, Haskell หรือ Ocaml ภาษาเหล่านี้แต่ละภาษามีล่ามแบบโต้ตอบเช่นเดียวกับคอมไพเลอร์ไปยังรหัสไบต์หรือรหัสเครื่องพื้นเมือง

ดังนั้นการจัดหมวดหมู่ภาษาโดย "รวบรวม" และ "ตีความ" จึงไม่สมเหตุสมผล


3
ฉันเห็นด้วย. หรือสมมติว่า: มีคอมไพเลอร์เนทีฟ (การสร้างรหัสเครื่องสำหรับ CPU ที่จะกิน) และคอมไพเลอร์ที่ไม่ใช่เจ้าของภาษา (การสร้างสิ่งที่โทเค็นเช่นรหัสกลางซึ่งคอมไพเลอร์เพียงครั้งเดียว หรือระหว่าง) รันไทม์ ONCE) และมีคอมไพเลอร์ "ของจริง" ที่ไม่เคยสร้างรหัสเครื่องและอย่าปล่อยให้ CPU รันโค้ด หลังคือล่าม วันนี้คอมไพเลอร์เนทีฟซึ่งผลิตรหัสเครื่องจักร (CPU) โดยตรง ณ เวลารวบรวมนั้นมีน้อยลงเรื่อย ๆ Delphi / Codegear เป็นหนึ่งในผู้รอดชีวิตที่ดีที่สุด
TheBlastOne

57

เริ่มคิดในแง่ของ: ระเบิดจากอดีต

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

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

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

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

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


1
ดีมาก - สรุปได้ดีในย่อหน้าสุดท้าย - ขอบคุณ!
ckib16

26

กรณีที่รุนแรงและเรียบง่าย:

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

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

ขอให้ฉันอธิบายว่าชีวิตไม่ใช่เรื่องง่ายอีกต่อไปแล้ว ตัวอย่างเช่น

  • ล่ามหลายคนจะรวบรวมรหัสที่ได้รับล่วงหน้าเพื่อให้ขั้นตอนการแปลไม่ต้องทำซ้ำอีกครั้ง
  • คอมไพเลอร์บางตัวไม่คอมไพล์ด้วยคำสั่งเครื่องเฉพาะ CPU แต่สำหรับ bytecode ซึ่งเป็นรหัสเครื่องเทียมสำหรับเครื่องที่สมมติขึ้น สิ่งนี้ทำให้โปรแกรมที่คอมไพล์แล้วพกพาได้มากกว่านี้ แต่ต้องการตัวแปล bytecode ในทุกระบบเป้าหมาย
  • ล่าม bytecode (ฉันกำลังดู Java ที่นี่) เมื่อเร็ว ๆ นี้มีแนวโน้มที่จะรวบรวม bytecode ที่พวกเขาได้รับสำหรับ CPU ของส่วนเป้าหมายก่อนดำเนินการ (เรียกว่า JIT) เพื่อประหยัดเวลามักจะทำเฉพาะกับรหัสที่ทำงานบ่อยครั้ง (ฮอตสปอต)
  • บางระบบที่มีหน้าตาและทำหน้าที่เหมือนล่าม (เช่น Clojure) จะรวบรวมโค้ดใด ๆ ที่พวกเขาได้รับทันที แต่อนุญาตการเข้าถึงแบบโต้ตอบกับสภาพแวดล้อมของโปรแกรม โดยพื้นฐานแล้วความสะดวกสบายของล่ามด้วยความเร็วในการรวบรวมไบนารี่
  • คอมไพเลอร์บางตัวไม่ได้คอมไพล์จริงๆพวกเขาเพียงแค่ทำการย่อยและบีบอัดโค้ด ฉันได้ยินมาพักนึงแล้วว่า Perl ทำงานอย่างไร ดังนั้นบางครั้งคอมไพเลอร์ก็กำลังทำงานอยู่เล็กน้อยและส่วนใหญ่ก็ยังตีความอยู่

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


23

จากhttp://www.quora.com/What-is-the-difference-between-compiled-and-interpreted-programming-languages

ไม่มีความแตกต่างเพราะ“ ภาษาการเขียนโปรแกรมที่คอมไพล์” และ“ ภาษาการเขียนโปรแกรมตีความ” ไม่ใช่แนวคิดที่มีความหมาย ภาษาการเขียนโปรแกรมใด ๆ และฉันหมายถึงใด ๆ สามารถตีความหรือเรียบเรียงได้ ดังนั้นการตีความและการรวบรวมเป็นเทคนิคการใช้งานไม่ใช่คุณลักษณะของภาษา

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

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

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


คุณช่วยแก้ไขประโยคนี้ได้ไหม: "มีคอมไพเลอร์ที่แปลภาษาอื่นเป็น JavaScript ซึ่งมักจะทำงานในเว็บเบราว์เซอร์ซึ่งอาจตีความจาวาสคริปต์หรือรวบรวมเป็นเครื่องเสมือนหรือรหัสเนทีฟ"
Koray Tugay

ถูกจับมัน ข้อผิดพลาดทั่วไปอีกประการหนึ่งคือการใช้ประโยชน์จากภาษากับ API ที่มีอยู่
Endian น้อย

10

ประโยชน์ที่ใหญ่ที่สุดของรหัสที่มาตีความมากกว่ารหัสที่มาเรียบเรียงเป็นพกพา

หากซอร์สโค้ดของคุณถูกคอมไพล์คุณจะต้องรวบรวมไฟล์ประมวลผลที่แตกต่างกันสำหรับโปรเซสเซอร์แต่ละประเภทและ / หรือแพลตฟอร์มที่คุณต้องการให้โปรแกรมของคุณทำงาน (เช่นหนึ่งสำหรับ Windows x86, หนึ่งสำหรับ Windows x64, หนึ่งสำหรับ Linux x64 และอื่น ๆ บน). นอกจากนี้หากรหัสของคุณเป็นไปตามมาตรฐานอย่างสมบูรณ์และไม่ได้ใช้ฟังก์ชั่น / ไลบรารีเฉพาะแพลตฟอร์มใด ๆ คุณจะต้องเขียนและรักษาฐานรหัสหลายฐาน!

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

ข้อดีของการคอมไพล์โค้ดคือมันซ่อนซอร์สโค้ดจากผู้ใช้ปลายทาง (ซึ่งอาจเป็นทรัพย์สินทางปัญญา ) เพราะแทนที่จะปรับใช้ซอร์สโค้ดต้นฉบับที่มนุษย์สามารถอ่านได้คุณจะปรับใช้ไฟล์ปฏิบัติการไบนารีที่ไม่ชัดเจน


1
ในแง่นี้ java ไม่สามารถพิจารณาได้ว่าเป็น "ภาษาที่คอมไพล์" แต่มันเป็นคอมไพล์เฟสที่ให้ข้อดีของการคอมไพล์ (การตรวจสอบประเภท, การตรวจหาข้อผิดพลาดเป็นต้น) และสร้าง bytecode ที่สามารถทำงานได้บนทุก OS ด้วย Java จัดเตรียมเครื่องเสมือน
Rogelio Triviño

7

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

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

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

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


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

4

ก่อนอื่นชี้แจง, Java ไม่ได้รวบรวมแบบคงที่และเชื่อมโยงในวิธี C ++ มันถูกรวบรวมเป็น bytecode ซึ่งจะถูกตีความโดย JVM JVM สามารถไปและทำการคอมไพล์ทันเวลากับภาษาเครื่องพื้นเมือง แต่ไม่จำเป็นต้องทำ

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

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

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

สำหรับการสร้าง executbles นั้นมีส่วนเกี่ยวข้องกับมันเพียงเล็กน้อย IMHO คุณสามารถสร้างไฟล์ที่เรียกทำงานได้จากภาษาที่คอมไพล์ แต่คุณยังสามารถสร้างไฟล์ที่เรียกใช้งานได้จากภาษาที่แปลยกเว้นล่ามและรันไทม์ที่ได้รับการบรรจุไว้ใน exectuable และซ่อนไว้จากคุณ ซึ่งหมายความว่าโดยทั่วไปคุณยังคงต้องจ่ายค่าใช้จ่ายรันไทม์ (แม้ว่าฉันแน่ใจว่าสำหรับบางภาษามีวิธีการแปลทุกอย่างเป็นแบบทรี)

ฉันไม่เห็นด้วยว่าทุกภาษาสามารถโต้ตอบได้ ภาษาบางภาษาเช่น C เชื่อมโยงกับเครื่องและโครงสร้างลิงก์ทั้งหมดซึ่งฉันไม่แน่ใจว่าคุณสามารถสร้างเวอร์ชันอินเทอร์แอคทีฟที่มีความหมายได้อย่างสมบูรณ์


C ไม่ได้ผูกติดอยู่กับ "เครื่องจักร" จริงๆ ไวยากรณ์และความหมายของ C ค่อนข้างง่าย ไม่ควรยากอย่างยิ่งที่จะใช้ตัวแปลภาษาซีใช้เวลานานมาก (เนื่องจากต้องใช้ไลบรารีมาตรฐานเช่นกัน) และ btw, Java สามารถรวบรวมเป็นรหัสเครื่องพื้นเมือง (ใช้ gcj)
Lunaryorn

@ Lunaryorn: ฉันไม่เห็นด้วยกับ GCJ GCJ ช่วยให้คุณมีสภาพแวดล้อมที่ทำงานได้ตามปกติ "แอปพลิเคชันที่คอมไพล์เชื่อมโยงกับรันไทม์ GCJ, libgcj, ซึ่งให้บริการไลบรารีคลาสหลัก, ตัวรวบรวมขยะและล่าม bytecode"
Uri

2
GCJ ไม่ผลิตรหัสเครื่องพื้นเมืองและไม่เพียง แต่สภาพแวดล้อมการปฏิบัติการด้วยล่ามฝังตัวและ bytecode libgcj จัดเตรียมล่าม bytecode เพื่อรองรับการโทรจากรหัสเนทีฟไปสู่ ​​Java bytecode ไม่ใช่เพื่อแปลโปรแกรมที่คอมไพล์ หาก libgcj ไม่ได้จัดเตรียมล่าม bytecode ไว้ GCJ จะไม่ปฏิบัติตามข้อกำหนดของ Java
Lunaryorn

@lunaryorn: อ่า ตกลงฉันขอขอบคุณที่ชี้แจงและยืนแก้ไข เราใช้ Java เป็นหลักในสภาพแวดล้อมของ windows ดังนั้นฉันไม่ได้ลอง gcj เป็นเวลาหลายปี
Uri


2

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


1
แน่นอนคุณสามารถสร้างคอมไพเลอร์สำหรับภาษาที่ตีความได้ แต่รหัสเครื่องที่คอมไพล์เป็นตัวสะท้อนของรันไทม์
Aiden Bell

2

The Python Book © 2015 Imagine Publishing Ltd เพียงแค่ทำให้ความแตกต่างแตกต่างออกไปตามคำใบ้ต่อไปนี้ที่กล่าวถึงในหน้า 10 ว่า:

ภาษาที่แปลเช่น Python เป็นภาษาที่แปลซอร์สโค้ดเป็นรหัสเครื่องแล้วดำเนินการทุกครั้งที่โปรแกรมทำงาน สิ่งนี้แตกต่างจากภาษาที่คอมไพล์เช่น C ซึ่งซอร์สโค้ดจะถูกแปลงเป็นรหัสเครื่องเพียงครั้งเดียว - รหัสเครื่องที่ได้จะถูกเรียกใช้งานในแต่ละครั้งที่โปรแกรมทำงาน


1

คอมไพล์เป็นกระบวนการสร้างโปรแกรมที่เรียกใช้งานได้จากโค้ดที่เขียนในภาษาโปรแกรมคอมไพล์ การคอมไพล์ทำให้คอมพิวเตอร์สามารถรันและเข้าใจโปรแกรมโดยไม่จำเป็นต้องใช้ซอฟต์แวร์การเขียนโปรแกรมที่ใช้ในการสร้าง เมื่อมีการคอมไพล์โปรแกรมมันมักจะถูกคอมไพล์สำหรับแพลตฟอร์มเฉพาะ (เช่นแพลตฟอร์ม IBM) ที่ทำงานกับคอมพิวเตอร์ที่เข้ากันได้กับ IBM แต่ไม่ใช่แพลตฟอร์มอื่น ๆ (เช่นแพลตฟอร์ม Apple) คอมไพเลอร์ตัวแรกได้รับการพัฒนาโดย Grace Hopper ขณะที่ทำงานกับคอมพิวเตอร์ Harvard Mark I วันนี้ภาษาระดับสูงส่วนใหญ่จะมีคอมไพเลอร์ของตัวเองหรือมีชุดเครื่องมือที่สามารถใช้ในการรวบรวมโปรแกรม ตัวอย่างที่ดีของคอมไพเลอร์ที่ใช้กับ Java คือ Eclipse และตัวอย่างของคอมไพเลอร์ที่ใช้กับ C และ C ++ คือคำสั่ง gcc


0

คำจำกัดความสั้น (ไม่แม่นยำ):

ภาษาที่คอมไพล์:โปรแกรมทั้งหมดแปลเป็นรหัสเครื่องในคราวเดียวจากนั้นรหัสเครื่องจะถูกเรียกใช้โดย CPU

ภาษาที่แปล:โปรแกรมอ่านทีละบรรทัดและทันทีที่บรรทัดอ่านคำสั่งเครื่องสำหรับบรรทัดนั้นจะถูกดำเนินการโดย CPU

แต่จริงๆแล้วภาษาไม่กี่วันที่รวบรวมหรือตีความอย่างหมดจดบ่อยครั้งมันเป็นส่วนผสม สำหรับคำอธิบายโดยละเอียดเกี่ยวกับรูปภาพดูที่กระทู้นี้:

ความแตกต่างระหว่างการรวบรวมและการตีความคืออะไร?

หรือโพสต์บล็อกของฉันในภายหลัง:

https://orangejuiceliberationfront.com/the-difference-between-compiler-and-interpreter/

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