มาโครคืออะไร ความแตกต่างระหว่างแมโครและฟังก์ชั่น?


16

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


15
คุณหมายถึงภาษาการเขียนโปรแกรมเฉพาะใด ๆ ?
mkrieger1

15
คุณจะต้องเฉพาะเจาะจงมากขึ้น มาโครอ้างถึงแนวคิดที่แตกต่างกันสามประการ ได้แก่ แมโครข้อความ / ตัวประมวลผลล่วงหน้าแบบ C, Lisp macros และแมโครแอปพลิเคชัน
chrylis -on

คำตอบ:


7

บันทึก

ฉันต้องการเพิ่มคำอธิบายต่อไปนี้หลังจากสังเกตรูปแบบการลงคะแนนโพลาไรซ์ของคำตอบนี้

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

ผมถือว่าคำตอบร่วมกันโดยJörg W Mittag มันเป็นการอ่านที่เฉียบแหลม (น้อยกว่าที่ฉันรู้) และฉันก็ยกมันขึ้นทันทีหลังจากโพสต์ ฉันเพิ่งเริ่มใช้งาน Software Engineering Stack Exchange และประสบการณ์และการสนทนาที่ผ่านมานั้นช่างลึกซึ้งจริงๆ

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


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

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

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

  • การใช้ค่าคงที่ (เช่นค่าทางคณิตศาสตร์หรือทางวิทยาศาสตร์) หรือพารามิเตอร์บางตัวของโปรแกรม

  • การพิมพ์ข้อความบันทึกหรือการจัดการการยืนยัน

  • ทำการคำนวณอย่างง่ายหรือตรวจสอบเงื่อนไข

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

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

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

ด้วยประสบการณ์ผู้เขียนโปรแกรมตัดสินใจอย่างมีวิจารณญาณว่าส่วนใดของรหัสจะเหมาะสมกับแมโครหรือฟังก์ชั่นในสถาปัตยกรรมโปรแกรมโดยรวม


9
ฟังก์ชั่นอินไลน์คืออะไร?
นาธานคูเปอร์

1
ในภาษา C & โคมาโครสามารถเรียกใช้ฟังก์ชันได้เช่นกัน ดังนั้นการสร้างความแตกต่างระหว่างทั้งสองจึงไม่สมเหตุสมผล
Sombrero Chicken

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

@ Sombrero Chicken: บางทีคุณสามารถแสดงตัวอย่างของสิ่งนั้นได้หรือไม่ คุณสามารถมีมาโครที่มีฟังก์ชั่นการโทร แต่ (AFAIK) แมโครไม่ได้เป็นการเรียกใช้ฟังก์ชัน
jamesqf

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

65

น่าเสียดายที่มีการใช้คำว่า "มาโคร" หลายรายการในการเขียนโปรแกรม

ในตระกูลภาษา Lisp และภาษาที่ได้รับแรงบันดาลใจจากพวกเขารวมถึงภาษาที่ใช้งานได้อย่างทันสมัยหรือได้รับแรงบันดาลใจจากการทำงานเช่น Scala และ Haskell รวมถึงภาษาที่จำเป็นบางอย่างเช่น Boo แมโครคือชิ้นส่วนของโค้ดที่ทำงานในเวลารวบรวม (หรืออย่างน้อยก่อนรันไทม์สำหรับการใช้งานโดยไม่มีคอมไพเลอร์) และสามารถแปลงทรีไวยากรณ์ไวยากรณ์ (หรืออะไรก็ตามที่เทียบเท่าในภาษาใดภาษาหนึ่งโดยเฉพาะเช่นใน Lisp มันจะเป็น S-Expressions) เป็นอย่างอื่นระหว่างการรวบรวม ตัวอย่างเช่นในการใช้งาน Scheme จำนวนมากforเป็นแมโครที่ขยายไปสู่การเรียกหลาย ๆ ตัวไปยังเนื้อหา ในภาษาที่พิมพ์แบบสแตติกมาโครมักจะพิมพ์ได้อย่างปลอดภัยเช่นพวกเขาไม่สามารถสร้างรหัสที่ไม่ได้พิมพ์ได้ดี

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

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

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

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


1
“ ในภาษาที่พิมพ์แบบสแตติกมาโครมักจะพิมพ์ได้อย่างปลอดภัยเช่นพวกเขาไม่สามารถสร้างรหัสที่ไม่ได้พิมพ์ได้ดี” - จริงเหรอ? คุณหมายถึงภาษาใด AFAICS ซึ่งโดยทั่วไปเป็นไปได้เฉพาะในการรับประกันในภาษาที่พิมพ์อย่างพึ่งพา ใน Haskell มาโคร TH มีความปลอดภัยทาง syntactically เท่านั้น แต่ตัวตรวจสอบประเภทจะทำงานหลังจากนั้น (เพื่อให้พิมพ์ได้อย่างชาญฉลาดพวกเขาให้การรับประกันน้อยกว่าแม่แบบ C ++)
leftaroundabout

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

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

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

1
@ jpmc26 ฉันจะบอกว่ารูปแบบทั่วไปคือการทดแทนที่คุณทำสิ่งเล็ก ๆ น้อย ๆ และมันจะขยายไปสู่เรื่องใหญ่ ภาษามาโคร M4 ไม่ได้มีไว้สำหรับรหัสโดยเฉพาะ คุณสามารถใช้มันเพื่อสร้างข้อความใด ๆ นอกจากนี้ยังมีมาโครคีย์บอร์ดเช่นคำตอบที่กล่าวถึงนี้ คุณกดปุ่ม 1 หรือ 2 และพวกมันจะขยายเป็นปุ่มกดจำนวนมากขึ้น vim macros ก็เช่นกัน บันทึกลำดับขนาดใหญ่ของคำสั่งโหมดปกติภายใต้คีย์เดียวและคุณเรียกลำดับนั้นโดยการรันคำสั่งโหมดปกติที่เรียกใช้งาน
JoL

2

ในตระกูลภาษา C นิยามแมโครคำสั่ง preprocessor ระบุเท็มเพลต parametrized ของโค้ดที่ถูกแทนที่ที่การเรียกแมโครโดยไม่ต้องคอมไพล์ที่นิยาม ซึ่งหมายความว่าตัวแปรอิสระทั้งหมดควรถูกผูกไว้ในบริบทของการเรียกแมโคร อาร์กิวเมนต์ของพารามิเตอร์ที่มีผลข้างเคียงเช่นi++สามารถทำซ้ำได้โดยการใช้พหูพจน์ของพารามิเตอร์ การทดแทนข้อความของการโต้แย้ง1 + 2ของพารามิเตอร์บางอย่างxเกิดขึ้นก่อนการรวบรวมและอาจทำให้เกิดพฤติกรรมที่ไม่คาดคิดx * 3( 7io 9) ข้อผิดพลาดในเนื้อความแมโครของคำจำกัดความของแมโครจะแสดงเฉพาะเมื่อรวบรวมที่การเรียกแมโคร

นิยามฟังก์ชันรหัสระบุด้วยตัวแปรอิสระที่ผูกไว้กับบริบทของร่างกายทำงานนั้น ไม่ได้เรียกใช้ฟังก์ชัน

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


2

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

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


0

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

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

เมื่อคำตอบของJörg W Mittagพูดถึงรายละเอียดที่แน่นอนแตกต่างกันไปในแต่ละภาษา: ในบางภาษาเช่น C, แมโครจะทำการทดแทนข้อความในซอร์สโค้ด ในบางอย่างเช่นเสียงกระเพื่อมมันดำเนินการจัดการของรูปแบบตัวกลางเช่นต้นไม้บทคัดย่อไวยากรณ์ นอกจากนี้ยังมีบางพื้นที่สีเทา: บางภาษามีสัญกรณ์สำหรับ "ฟังก์ชั่นแบบอินไลน์" ซึ่งถูกกำหนดเช่นฟังก์ชั่น แต่ขยายเข้าไปในโปรแกรมที่คอมไพล์เช่นแมโคร

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


0

แมโครถูกเรียกใช้งานระหว่างการคอมไพล์และฟังก์ชันถูกเรียกใช้ในขณะใช้งาน

ตัวอย่าง:

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