ฉันไม่เข้าใจแนวคิดมาโครอย่างดี มาโครคืออะไร ฉันไม่เข้าใจว่ามันแตกต่างจากฟังก์ชั่นอย่างไร ทั้งฟังก์ชั่นและมาโครมีบล็อกของรหัส ดังนั้นมาโครและฟังก์ชั่นต่างกันอย่างไร
ฉันไม่เข้าใจแนวคิดมาโครอย่างดี มาโครคืออะไร ฉันไม่เข้าใจว่ามันแตกต่างจากฟังก์ชั่นอย่างไร ทั้งฟังก์ชั่นและมาโครมีบล็อกของรหัส ดังนั้นมาโครและฟังก์ชั่นต่างกันอย่างไร
คำตอบ:
ฉันต้องการเพิ่มคำอธิบายต่อไปนี้หลังจากสังเกตรูปแบบการลงคะแนนโพลาไรซ์ของคำตอบนี้
คำตอบนั้นไม่ได้ถูกเขียนขึ้นโดยคำนึงถึงความถูกต้องทางเทคนิคและความเห็นทั่วไปในวงกว้าง มันเป็นความพยายามที่อ่อนน้อมถ่อมตนที่จะอธิบายในภาษาที่เรียบง่ายความแตกต่างระหว่างมาโครและฟังก์ชั่นกับมือใหม่ในการเขียนโปรแกรมโดยไม่ต้องพยายามให้เสร็จสมบูรณ์หรือถูกต้อง ภาษาการเขียนโปรแกรม C อยู่ในใจของฉันเมื่อร่างคำตอบ แต่ฉันขอโทษที่ไม่ได้พูดถึงมันอย่างชัดเจนและทำให้เกิดความสับสน (อาจเกิดขึ้น)
ผมถือว่าคำตอบร่วมกันโดยJörg W Mittag มันเป็นการอ่านที่เฉียบแหลม (น้อยกว่าที่ฉันรู้) และฉันก็ยกมันขึ้นทันทีหลังจากโพสต์ ฉันเพิ่งเริ่มใช้งาน Software Engineering Stack Exchange และประสบการณ์และการสนทนาที่ผ่านมานั้นช่างลึกซึ้งจริงๆ
ฉันจะทิ้งคำตอบนี้ไว้ที่นี่เพราะมันอาจจะเป็นประโยชน์สำหรับมือใหม่ในการพัฒนาซอฟต์แวร์อื่น ๆ พยายามที่จะเข้าใจแนวคิดโดยไม่ต้องจมอยู่กับความถูกต้องทางเทคนิค
ทั้งมาโครและฟังก์ชั่นเป็นตัวแทนของรหัสที่มีอยู่ในตัวเอง พวกเขาทั้งคู่เป็นเครื่องมือที่ช่วยในการออกแบบโมดูลของโปรแกรม จากมุมมองของโปรแกรมเมอร์ที่กำลังเขียนซอร์สโค้ดมันจะค่อนข้างคล้ายกัน อย่างไรก็ตามพวกเขาแตกต่างกันในวิธีการจัดการในช่วงระยะเวลาการดำเนินการโปรแกรม
แมโครถูกกำหนดหนึ่งครั้งและใช้ในหลาย ๆ ที่ในโปรแกรม มาโครได้รับการขยายแบบอินไลน์ในระหว่างขั้นตอนการประมวลผลล่วงหน้า ดังนั้นในทางเทคนิคแล้วมันไม่ได้เป็นเอนทิตีที่แยกต่างหากเมื่อคอมไพล์ซอร์สโค้ดถูกรวบรวม คำสั่งในนิยามแมโครจะกลายเป็นส่วนหนึ่งของคำแนะนำโปรแกรมเช่นเดียวกับข้อความอื่น ๆ
แรงจูงใจเบื้องหลังการเขียนแมโครคือการทำให้การเขียนและการจัดการซอร์สโค้ดง่ายขึ้นสำหรับโปรแกรมเมอร์ โดยทั่วไปแล้วจะต้องการมาโครสำหรับงานที่ง่ายกว่าซึ่งการเขียนฟังก์ชั่นแบบเต็มเปี่ยมจะเป็นค่าใช้จ่ายด้านประสิทธิภาพ / ค่าปรับในการใช้งานจริง ตัวอย่างของสถานการณ์ที่แมโคใช้งานได้ดีกว่าฟังก์ชั่นคือ:
การใช้ค่าคงที่ (เช่นค่าทางคณิตศาสตร์หรือทางวิทยาศาสตร์) หรือพารามิเตอร์บางตัวของโปรแกรม
การพิมพ์ข้อความบันทึกหรือการจัดการการยืนยัน
ทำการคำนวณอย่างง่ายหรือตรวจสอบเงื่อนไข
เมื่อใช้มาโครคุณสามารถทำการเปลี่ยนแปลง / แก้ไขได้อย่างง่ายดายในที่เดียวซึ่งสามารถใช้งานได้ทันทีทุกที่ที่ใช้มาโครในโปรแกรม จำเป็นต้องมีการคอมไพล์ใหม่ของโปรแกรมเพื่อให้การเปลี่ยนแปลงมีผล
รหัสฟังก์ชั่นในอีกทางหนึ่งจะถูกรวบรวมเป็นหน่วยแยกต่างหากภายในโปรแกรมและได้รับการโหลดในหน่วยความจำระหว่างการทำงานของโปรแกรมเฉพาะเมื่อจำเป็น รหัสฟังก์ชั่นยังคงเป็นเอกลักษณ์ที่เป็นอิสระจากส่วนที่เหลือของโปรแกรม รหัสที่โหลดจะถูกนำกลับมาใช้ใหม่หากมีการเรียกใช้ฟังก์ชันมากกว่าหนึ่งครั้ง เมื่อพบการเรียกใช้ฟังก์ชั่นในโปรแกรมที่กำลังทำงานระบบจะส่งผ่านการควบคุมไปยังระบบย่อยรันไทม์และบริบทของโปรแกรมที่กำลังทำงานอยู่
อย่างไรก็ตามมีการปรับประสิทธิภาพเล็กน้อยที่ต้องพบเมื่อเรียกใช้ฟังก์ชัน (การสลับบริบทรักษาที่อยู่ผู้ส่งของคำสั่งโปรแกรมหลักผ่านพารามิเตอร์และการจัดการค่าส่งคืนเป็นต้น) ดังนั้นการใช้ฟังก์ชั่นจึงเป็นที่ต้องการสำหรับกลุ่มของโค้ดที่ซับซ้อนเท่านั้น (เทียบกับมาโครที่จัดการเคสที่ง่ายกว่า)
ด้วยประสบการณ์ผู้เขียนโปรแกรมตัดสินใจอย่างมีวิจารณญาณว่าส่วนใดของรหัสจะเหมาะสมกับแมโครหรือฟังก์ชั่นในสถาปัตยกรรมโปรแกรมโดยรวม
น่าเสียดายที่มีการใช้คำว่า "มาโคร" หลายรายการในการเขียนโปรแกรม
ในตระกูลภาษา Lisp และภาษาที่ได้รับแรงบันดาลใจจากพวกเขารวมถึงภาษาที่ใช้งานได้อย่างทันสมัยหรือได้รับแรงบันดาลใจจากการทำงานเช่น Scala และ Haskell รวมถึงภาษาที่จำเป็นบางอย่างเช่น Boo แมโครคือชิ้นส่วนของโค้ดที่ทำงานในเวลารวบรวม (หรืออย่างน้อยก่อนรันไทม์สำหรับการใช้งานโดยไม่มีคอมไพเลอร์) และสามารถแปลงทรีไวยากรณ์ไวยากรณ์ (หรืออะไรก็ตามที่เทียบเท่าในภาษาใดภาษาหนึ่งโดยเฉพาะเช่นใน Lisp มันจะเป็น S-Expressions) เป็นอย่างอื่นระหว่างการรวบรวม ตัวอย่างเช่นในการใช้งาน Scheme จำนวนมากfor
เป็นแมโครที่ขยายไปสู่การเรียกหลาย ๆ ตัวไปยังเนื้อหา ในภาษาที่พิมพ์แบบสแตติกมาโครมักจะพิมพ์ได้อย่างปลอดภัยเช่นพวกเขาไม่สามารถสร้างรหัสที่ไม่ได้พิมพ์ได้ดี
ในตระกูลภาษา C มาโครเป็นเหมือนการแทนที่ด้วยข้อความ ซึ่งหมายความว่าพวกเขาสามารถสร้างรหัสที่ไม่ได้พิมพ์ได้ดีหรือไม่ถูกกฎหมาย syntactically
ในมาโครแอสเซมเบลอร์ "มาโคร" อ้างถึง "คำแนะนำเสมือน" คือคำสั่งที่ CPU ไม่รองรับ แต่กำเนิดซึ่งมีประโยชน์และแอสเซมเบลอร์อนุญาตให้คุณใช้คำสั่งเหล่านั้นและจะขยายออกเป็นหลายคำสั่งที่ CPU เข้าใจ .
ในการเขียนสคริปต์แอปพลิเคชัน "แมโคร" หมายถึงชุดของการกระทำที่ผู้ใช้สามารถ "บันทึก" และ "เล่น"
ทั้งหมดนี้อยู่ในรูปแบบของโค้ดที่สามารถเรียกใช้งานได้ซึ่งหมายความว่าพวกมันสามารถถูกมองว่าเป็นฟังก์ชั่น อย่างไรก็ตามในกรณีของมาโคร Lisp เช่นอินพุทและเอาท์พุทเป็นแฟรกเมนต์ของโปรแกรม ในกรณีของ C อินพุตและเอาต์พุตเป็นโทเค็น สามคนแรกนอกจากนี้ยังมีความแตกต่างที่สำคัญมากที่พวกเขาจะดำเนินการที่รวบรวมเวลา ในความเป็นจริง, C แมโคร preprocessor เป็นชื่อที่แสดงถึงจะดำเนินการจริงก่อนโค้ดถึงแม้คอมไพเลอร์
ในตระกูลภาษา C นิยามแมโครคำสั่ง preprocessor ระบุเท็มเพลต parametrized ของโค้ดที่ถูกแทนที่ที่การเรียกแมโครโดยไม่ต้องคอมไพล์ที่นิยาม ซึ่งหมายความว่าตัวแปรอิสระทั้งหมดควรถูกผูกไว้ในบริบทของการเรียกแมโคร อาร์กิวเมนต์ของพารามิเตอร์ที่มีผลข้างเคียงเช่นi++
สามารถทำซ้ำได้โดยการใช้พหูพจน์ของพารามิเตอร์ การทดแทนข้อความของการโต้แย้ง1 + 2
ของพารามิเตอร์บางอย่างx
เกิดขึ้นก่อนการรวบรวมและอาจทำให้เกิดพฤติกรรมที่ไม่คาดคิดx * 3
( 7
io 9
) ข้อผิดพลาดในเนื้อความแมโครของคำจำกัดความของแมโครจะแสดงเฉพาะเมื่อรวบรวมที่การเรียกแมโคร
นิยามฟังก์ชันรหัสระบุด้วยตัวแปรอิสระที่ผูกไว้กับบริบทของร่างกายทำงานนั้น ไม่ได้เรียกใช้ฟังก์ชัน
แมโคร แต่ดูเหมือนเชิงลบให้การเข้าถึงการโทรหมายเลขบรรทัดและแหล่งที่มาของไฟล์อาร์กิวเมนต์เป็นสตริง
ในแง่นามธรรมที่มากกว่าเล็กน้อยแมโครจะใช้ไวยากรณ์ในฐานะที่เป็นหน้าที่ของข้อมูล ฟังก์ชั่น (ในนามธรรม) สรุปการเปลี่ยนแปลงของข้อมูล มันใช้ข้อโต้แย้งของมันเป็นข้อมูลที่ประเมินดำเนินการบางอย่างกับพวกเขาและส่งกลับผลลัพธ์ซึ่งเป็นเพียงข้อมูล
ในทางตรงกันข้ามแมโครจะใช้ไวยากรณ์ที่ไม่ได้รับการประเมินและดำเนินการกับเรื่องนั้น สำหรับภาษาที่มีลักษณะคล้ายภาษา C ไวยากรณ์จะอยู่ในระดับโทเค็น สำหรับภาษาที่มีมาโครคล้าย LISP จะได้รับไวยากรณ์ที่แสดงเป็น AST แมโครจะต้องส่งคืนกลุ่มไวยากรณ์ใหม่
แมโครโดยทั่วไปหมายถึงบางสิ่งบางอย่างที่มีการขยายตัวในสถานที่เปลี่ยนแมโคร "เรียกว่า" ในระหว่างการรวบรวมหรือก่อนการประมวลผลที่มีคำแนะนำในแต่ละภาษาเป้าหมาย ณ รันไทม์โดยทั่วไปจะไม่มีข้อบ่งชี้ว่ามาโครเริ่มต้นและสิ้นสุดที่ใด
นี้แตกต่างจากย่อยซึ่งเป็นชิ้นส่วนที่นำมาใช้ใหม่รหัสซึ่งตั้งอยู่แยกต่างหากในหน่วยความจำที่ควบคุมจะถูกส่งผ่านไปที่รันไทม์ "ฟังก์ชั่น", "โพรซีเดอร์" และ "เมธอด" ในภาษาการเขียนโปรแกรมส่วนใหญ่อยู่ในหมวดหมู่นี้
เมื่อคำตอบของJörg W Mittagพูดถึงรายละเอียดที่แน่นอนแตกต่างกันไปในแต่ละภาษา: ในบางภาษาเช่น C, แมโครจะทำการทดแทนข้อความในซอร์สโค้ด ในบางอย่างเช่นเสียงกระเพื่อมมันดำเนินการจัดการของรูปแบบตัวกลางเช่นต้นไม้บทคัดย่อไวยากรณ์ นอกจากนี้ยังมีบางพื้นที่สีเทา: บางภาษามีสัญกรณ์สำหรับ "ฟังก์ชั่นแบบอินไลน์" ซึ่งถูกกำหนดเช่นฟังก์ชั่น แต่ขยายเข้าไปในโปรแกรมที่คอมไพล์เช่นแมโคร
ภาษาส่วนใหญ่สนับสนุนให้โปรแกรมเมอร์ให้เหตุผลเกี่ยวกับแต่ละรูทีนย่อยในการแยกการกำหนดสัญญาประเภทสำหรับอินพุตและเอาท์พุทและการซ่อนข้อมูลอื่น ๆ เกี่ยวกับรหัสการโทร มักจะมีผลกระทบต่อประสิทธิภาพในการเรียกรูทีนย่อยซึ่งมาโครไม่ได้เกิดขึ้นและมาโครอาจสามารถจัดการโปรแกรมด้วยวิธีที่รูทีนย่อยไม่สามารถทำได้ มาโครอาจได้รับการพิจารณาว่า "ระดับต่ำกว่า" รูทีนย่อยเนื่องจากทำงานบนพื้นฐานที่เป็นนามธรรมน้อยกว่า
แมโครถูกเรียกใช้งานระหว่างการคอมไพล์และฟังก์ชันถูกเรียกใช้ในขณะใช้งาน
ตัวอย่าง:
#include <stdio.h>
#define macro_sum(x,y) (x+y)
int func_sum(x,y) {
return x+y;
}
int main(void) {
printf("%d\n", macro_sum(2,3));
printf("%d\n", func_sum(2,3));
return 0;
}
ดังนั้นระหว่างการรวบรวมรหัสจึงเปลี่ยนเป็น:
#include <stdio.h>
int func_sum(x,y) {
return x+y;
}
int main(void) {
printf("%d\n", (2+3));
printf("%d\n", func_sum(2,3));
return 0;
}