ทำไมมาโครไม่รวมอยู่ในภาษาการเขียนโปรแกรมที่ทันสมัยที่สุด?


31

ฉันรู้ว่าพวกเขานำมาใช้อย่างไม่ปลอดภัยใน C / C ++ พวกเขาไม่สามารถนำไปใช้ในทางที่ปลอดภัยยิ่งขึ้น? ข้อเสียของมาโครนั้นแย่มากพอที่จะเทียบกับพลังมหาศาลที่พวกเขามีให้หรือไม่?


4
มาโครใดที่ให้พลังงานที่ไม่สามารถทำได้อย่างง่ายดายในอีกทางหนึ่ง?
Chinmay Kanchi

2
ใน C # ใช้ส่วนขยายภาษาหลักเพื่อห่อการสร้างคุณสมบัติอย่างง่ายและเขตข้อมูลสำรองลงในการประกาศเดียว และสิ่งนี้ใช้เวลามากกว่าแมโครศัพท์: คุณจะสร้างคุณสมบัติที่สอดคล้องกับWithEventsตัวดัดแปลงของ Visual Basic ได้อย่างไร คุณต้องการบางสิ่งเช่นแมโครความหมาย
Jeffrey Hantin

3
ปัญหาเกี่ยวกับมาโครก็คือเช่นเดียวกับกลไกอันทรงพลังทั้งหมดมันทำให้โปรแกรมเมอร์สามารถทำลายสมมุติฐานที่คนอื่นทำหรือจะทำ สมมติฐานเป็นกุญแจสำคัญในการให้เหตุผลและไม่มีความสามารถในการให้เหตุผลที่เป็นไปได้เกี่ยวกับตรรกะการทำให้ความคืบหน้ากลายเป็นสิ่งต้องห้าม
dan_waterworth

2
@Chinmay: macros สร้างรหัส ไม่มีคุณสมบัติในภาษา Java ที่มีพลังนั้น
kevin cline

1
@Chinmay Kanchi: แมโครอนุญาตให้เรียกใช้งานโค้ด (ประเมิน) ณ เวลารวบรวมแทนที่จะเป็นเวลาทำงาน
Giorgio

คำตอบ:


57

ผมคิดว่าเหตุผลหลักคือแมโครเป็นคำศัพท์ สิ่งนี้มีผลกระทบหลายประการ:

  • คอมไพเลอร์ไม่มีวิธีตรวจสอบว่าแมโครถูกปิดความหมายนั่นคือมันหมายถึง "หน่วยความหมาย" เหมือนฟังก์ชั่น (พิจารณา#define TWO 1+1- อะไรจะTWO*TWOเท่ากัน 3. )

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

  • หากรหัสไม่ได้รวบรวมคอมไพเลอร์ไม่มีทางรู้ได้ว่าข้อผิดพลาดนั้นอยู่ในตัวแมโครหรือสถานที่ที่ใช้แมโคร คอมไพเลอร์จะรายงานความผิดครึ่งเวลาหรือต้องรายงานทั้งคู่แม้ว่าหนึ่งในนั้นอาจจะใช้ได้ (พิจารณา#define min(x,y) (((x)<(y))?(x):(y)): คอมไพเลอร์ควรทำอย่างไรหากประเภทxและyไม่ตรงกันหรือไม่นำไปใช้operator<)

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

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

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


32
ไม่ใช่มาโครภาษาทั้งหมดที่มีคำศัพท์ ตัวอย่างเช่นมาโคร Scheme เป็นวากยสัมพันธ์และเทมเพลต C ++ นั้นมีความหมาย ระบบคำศัพท์มาโครมีความแตกต่างที่พวกเขาสามารถยึดกับภาษาใด ๆ โดยไม่ได้ตระหนักถึงไวยากรณ์
Jeffrey Hantin

8
@ เจฟฟรีย์: ฉันคิดว่า "มาโครเป็นคำศัพท์" ของฉันนั้นสั้นมากสำหรับ“ เมื่อผู้คนอ้างถึงมาโครในภาษาการเขียนโปรแกรมพวกเขามักนึกถึงมาโครศัพท์” โชคไม่ดีที่ Scheme จะใช้คำที่โหลดนี้สำหรับบางสิ่งที่แตกต่างกันโดยพื้นฐาน อย่างไรก็ตามเทมเพลต C ++ ไม่ได้ถูกอ้างถึงอย่างกว้างขวางว่าเป็นมาโครอย่างแม่นยำเนื่องจากมันไม่ได้เป็นคำศัพท์ทั้งหมด
Timwi

25
ฉันคิดว่าการใช้คำของมาโครใน Scheme นั้นย้อนกลับไปที่ Lisp ซึ่งอาจหมายถึงว่ามันใช้มาก่อนการใช้งานอื่น ๆ IIRC C / C ++ ระบบเดิมเรียกว่าpreprocessor
Bevan

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

13

แต่ใช่แมโครสามารถออกแบบและใช้งานได้ดีกว่าใน C / C ++

ปัญหาเกี่ยวกับมาโครคือการที่พวกเขาเป็นกลไกการขยายไวยากรณ์ภาษาได้อย่างมีประสิทธิภาพที่เขียนรหัสของคุณลงในสิ่งอื่น

  • ในกรณี C / C ++ ไม่มีการตรวจสติพื้นฐาน หากคุณระวังสิ่งต่างๆก็โอเค หากคุณทำผิดพลาดหรือถ้าคุณใช้มากเกินไปคุณจะเจอปัญหาใหญ่

    เพิ่มสิ่งนี้ที่สิ่งง่าย ๆ มากมายที่คุณสามารถทำได้ด้วยมาโคร (สไตล์ C / C ++) สามารถทำได้ด้วยวิธีอื่นในภาษาอื่น

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


บริบททางประวัติศาสตร์โดยย่อ

แมโคร (ย่อมาจากคำแนะนำการใช้แมโคร) ปรากฏขึ้นครั้งแรกในบริบทของภาษาแอสเซมบลี จากวิกิพีเดียแมโครนั้นมีอยู่ในแอสเซมบลี IBM บางตัวในปี 1950

LISP ดั้งเดิมไม่มีมาโคร แต่เป็นครั้งแรกที่นำมาใช้กับ MacLisp ในช่วงกลางปี ​​1960: https://stackoverflow.com/questions/3065606/when-did-the-idea-of-macros-user-defined-code -transformation http://www.csee.umbc.edu/courses/331/resources/papers/Evolution-of-Lisp.pdf ก่อนหน้านั้น "fexprs" ได้จัดเตรียมฟังก์ชันการทำงานคล้ายกับมาโคร

รุ่นแรกสุดของ C ไม่มีมาโคร ( http://cm.bell-labs.com/cm/cs/who/dmr/chist.html ) สิ่งเหล่านี้ถูกเพิ่มเข้ามาประมาณปี 1972-73 ผ่านตัวประมวลผลล่วงหน้า ก่อนที่ C สนับสนุนเฉพาะและ#include#define

ตัวประมวลผลล่วงหน้าของแมโคร M4 นั้นมีต้นกำเนิดในปี 1977

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

ดังนั้นเมื่อมีคนพูดถึงความเป็นอันดับหนึ่งของคำนิยามเฉพาะของคำว่า "มาโคร" มันเป็นสิ่งสำคัญที่จะต้องทราบว่าความหมายนั้นได้วิวัฒนาการไปตามกาลเวลา


9
C ++ ได้รับพร (?) กับระบบมาโครสองระบบ: ตัวประมวลผลล่วงหน้าและการขยายเทมเพลต
Jeffrey Hantin

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

@Dunk คำจำกัดความของแมโครเหมือนกับใน Lisp ถือเป็นความเข้าใจที่โง่เง่า "ทันสมัย" เหมือนกับในตัวประมวลผลล่วงหน้า C ที่น่าสมเพช
SK-logic

@SK: เป็นการดีกว่าหรือที่จะ "ถูกต้องตามหลักวิชาการ" ให้ถูกต้องและทำให้สับสนในการสนทนาหรือดีกว่าที่จะเข้าใจ?
Dunk

1
@Dunk คำศัพท์ไม่ได้เป็นเจ้าของโดยพยุหะไม่รู้ ไม่ควรนำมาพิจารณาด้วยความไม่รู้ของพวกเขามิฉะนั้นมันจะนำไปสู่การลดทอนความรู้วิทยาศาสตร์คอมพิวเตอร์ทั้งหมด หากใครบางคนเข้าใจ "แมโคร" เพียงเพื่อการอ้างอิงถึงตัวประมวลผลล่วงหน้า C ไม่มีอะไรเลยนอกจากความไม่รู้ ฉันสงสัยว่ามีสัดส่วนที่สำคัญของคนที่ไม่เคยได้ยิน Lisp หรือแม้แต่ของ pardonnez mon français, VBA "macros" ใน Office
SK-logic

12

มาโครสามารถบันทึกได้ตามตรรกะของสกอตต์ แน่นอนว่าฟังก์ชั่นคลาสไลบรารีและอุปกรณ์ทั่วไปอื่น ๆ

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

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

ดังนั้นสำหรับภาษาที่ต้องการลดความซับซ้อนของการเขียนโปรแกรม (เช่น Java หรือ Python) ระบบดังกล่าวเป็นคำสาปแช่ง


3
จากนั้น Java ก็ออกจากรางรถไฟโดยเพิ่ม foreach, คำอธิบายประกอบ, การยืนยัน, generics-by-erasure, ...
Jeffrey Hantin

2
@ Jeffrey: และอย่าลืมเครื่องกำเนิดรหัสบุคคลที่สามมากมาย ในความคิดที่สองเราลืมสิ่งเหล่านั้น
Shog9

4
อีกตัวอย่างของวิธีการที่ Java เป็นแบบง่ายแทนที่จะเป็นแบบง่าย
Jeffrey Hantin

3
@JeffreyHantin: มีอะไรผิดปกติกับ foreach?
Casebash

1
@Dunk อุปมานี้อาจจะยืด ... แต่ฉันคิดว่าการเพิ่มความสามารถทางภาษานั้นเป็นเหมือนพลูโทเนียม มีราคาแพงในการติดตั้งยากที่จะกลึงเป็นรูปร่างที่ต้องการและอันตรายอย่างน่าทึ่งหากใช้ผิดวัตถุประสงค์
Jeffrey Hantin

6

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

ตัวอย่างของความง่ายของมาโครที่สามารถเป็นตัวอย่าง Clojure ซึ่งระบุค่าเริ่มต้นที่จะใช้ในกรณีของข้อยกเว้น:

(defmacro on-error [default-value code]
  `(try ~code (catch Exception ~'e ~default-value)))

(on-error 0 (+ nil nil))               ;; would normally throw NullPointerException
=> 0                                   ;l; but we get the default value

แม้ว่าใน Lisps คำแนะนำทั่วไปคือ "อย่าใช้มาโครเว้นแต่คุณจำเป็นต้องทำ"

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

  • มาโครแบบข้อความ - เช่นตัวประมวลผลล่วงหน้า C - ง่ายต่อการใช้งาน แต่ยุ่งยากมากที่จะใช้อย่างถูกต้องตามที่คุณต้องการสร้างไวยากรณ์ต้นฉบับที่ถูกต้องในรูปแบบข้อความรวมถึง quirks เกี่ยวกับการสร้างประโยค
  • DSLS ที่ใช้มาโคร - เช่นระบบเทมเพลต C ++ คอมเพล็กซ์อาจส่งผลให้เกิดความยุ่งยากในการซิงก์ได้ซับซ้อนมากสำหรับคอมไพเลอร์และผู้เขียนเครื่องมือในการจัดการอย่างถูกต้องเนื่องจากมันนำเสนอความซับซ้อนใหม่ที่สำคัญในไวยากรณ์ภาษาและความหมาย
  • API การจัดการ AST / bytecode - เช่นการสร้าง Java reflection / bytecode - ในทางทฤษฎีมีความยืดหยุ่นสูง แต่สามารถรับได้มาก: มันต้องใช้โค้ดจำนวนมากเพื่อทำสิ่งที่ง่ายมาก หากใช้โค้ดสิบบรรทัดเพื่อสร้างฟังก์ชันเทียบเท่ากับสามบรรทัดคุณจะไม่ได้รับประโยชน์มากนักจากความพยายามในการเขียนโปรแกรมเมตา ...

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


ฮึ. รหัส "ไม่เป็นข้อมูลเป็นสิ่งที่ดี" ขยะ รหัสคือรหัสข้อมูลคือข้อมูลและการแยกทั้งสองนั้นเป็นช่องโหว่ความปลอดภัยไม่ถูกต้อง คุณจะคิดว่าการเกิดขึ้นของ SQL Injection เป็นหนึ่งในคลาสที่มีช่องโหว่ที่ใหญ่ที่สุดในการดำรงอยู่จะทำให้เสียความคิดในการสร้างรหัสและข้อมูลที่สามารถเปลี่ยนได้อย่างง่ายดายเพียงครั้งเดียว
Mason Wheeler

10
@ Mason - ฉันไม่คิดว่าคุณเข้าใจแนวคิด code-is-data ซอร์สโค้ดโปรแกรม C ทั้งหมดยังเป็นข้อมูล - มันเพิ่งเกิดขึ้นที่จะแสดงในรูปแบบข้อความ Lisps เหมือนกันยกเว้นพวกเขาแสดงรหัสในโครงสร้างข้อมูลระดับกลางที่ใช้งานได้จริง (s-expressions) ที่ช่วยให้สามารถจัดการและแปลงโดยแมโครก่อนการคอมไพล์ ในทั้งสองกรณีการส่งอินพุตที่ไม่น่าเชื่อถือไปยังคอมไพเลอร์อาจเป็นช่องโหว่ความปลอดภัย - แต่มันยากที่จะทำโดยไม่ตั้งใจและมันจะเป็นความผิดของคุณในการทำสิ่งที่โง่ไม่ใช่ของคอมไพเลอร์
mikera

สนิมเป็นอีกระบบแมโครที่ปลอดภัยที่น่าสนใจ มีกฎ / ความหมายที่เข้มงวดเพื่อหลีกเลี่ยงชนิดของปัญหาที่เกี่ยวข้องกับมาโครศัพท์ C / C ++ และใช้ DSL เพื่อดักจับส่วนต่าง ๆ ของนิพจน์อินพุตลงในตัวแปรมาโครเพื่อแทรกในภายหลัง มันไม่มีประสิทธิภาพเท่ากับความสามารถของ Lisps ในการเรียกใช้ฟังก์ชันใด ๆ ในอินพุต แต่ให้ชุดแมโครการจัดการที่มีประโยชน์มากมายซึ่งสามารถเรียกได้จากมาโครอื่น
zstewart

ฮึ. ขยะความปลอดภัยไม่มาก มิฉะนั้นตำหนิทุกระบบที่มีสถาปัตยกรรมในตัวของ von Neumann เช่นโปรเซสเซอร์ IA-32 ทุกตัวที่มีความสามารถในการแก้ไขรหัสด้วยตนเอง ฉันสงสัยว่าคุณจะสามารถเติมเต็มหลุมในร่างกายได้หรือไม่ ... อย่างไรก็ตามคุณต้องเผชิญกับความจริงโดยทั่วไป: การขาดคุณสมบัติระหว่างรหัสและข้อมูลนั้นเป็นลักษณะของโลกในหลาย ๆด้าน และคุณก็เป็นโปรแกรมเมอร์ที่มีหน้าที่รักษาความมั่นคงของข้อกำหนดด้านความปลอดภัยซึ่งไม่เหมือนกับการใช้การแยกแบบผิด ๆ ก่อนกำหนดที่ใดก็ได้
FrankHB

4

ในการตอบคำถามของคุณให้คิดถึงว่ามาโครใดที่ใช้งานเป็นส่วนใหญ่ (คำเตือน: โค้ดที่คอมไพล์ด้วยสมอง)

  • มาโครใช้เพื่อกำหนดค่าคงที่เชิงสัญลักษณ์ #define X 100

สิ่งนี้สามารถถูกแทนที่ด้วย: const int X = 100;

  • มาโครใช้เพื่อกำหนดฟังก์ชั่นประเภทผู้ไม่เชื่อเรื่องพระเจ้าแบบอินไลน์ #define max(X,Y) (X>Y?X:Y)

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

  • มาโครใช้เพื่อระบุทางลัดไปยังองค์ประกอบที่ใช้บ่อย #define p printf

สิ่งนี้ถูกแทนที่อย่างง่ายดายด้วยฟังก์ชั่นp()ที่ทำสิ่งเดียวกัน นี่ค่อนข้างเกี่ยวข้องกับ C (ต้องการให้คุณใช้va_arg()ตระกูลของฟังก์ชัน) แต่ในภาษาอื่น ๆ อีกมากมายที่รองรับจำนวนตัวแปรของฟังก์ชันอาร์กิวเมนต์มันง่ายกว่ามาก

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

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


1
หากคุณต้อง #define max โปรดใส่เครื่องหมายวงเล็บไว้รอบ ๆ พารามิเตอร์ดังนั้นจึงไม่มีผลกระทบที่ไม่คาดคิดจากลำดับความสำคัญของผู้ปฏิบัติงาน ... เช่น #define max (X, Y) ((X)> (Y)? (X) :( Y))
foo

คุณรู้ว่ามันเป็นเพียงตัวอย่าง ... เจตนาคือแสดงให้เห็น
Chinmay Kanchi

+1 สำหรับการจัดการกับเรื่องนี้อย่างเป็นระบบ ฉันชอบที่จะเพิ่มการรวบรวมตามเงื่อนไขสามารถกลายเป็นฝันร้ายได้อย่างง่ายดาย - ฉันจำได้ว่ามีโปรแกรมชื่อ "unifdef" (??) ซึ่งมีจุดประสงค์เพื่อทำให้มองเห็นสิ่งที่เหลืออยู่หลังจากการประมวลผลภายหลัง
Ingo

7
In fact, I can't think of a single use-case for macros that can't easily be duplicated in another way: อย่างน้อยใน C คุณไม่สามารถสร้างตัวระบุ (ชื่อตัวแปร) โดยใช้การต่อโทเค็นได้โดยไม่ต้องใช้มาโคร
Charles Salvia

มาโครทำให้สามารถตรวจสอบให้แน่ใจว่ารหัสและโครงสร้างข้อมูลบางอย่างยังคง "ขนาน" ตัวอย่างเช่นหากมีเงื่อนไขจำนวนน้อยที่มีข้อความที่เกี่ยวข้องและหนึ่งจะต้องยืนยันพวกเขาในรูปแบบที่รัดกุมพยายามที่จะใช้enumเพื่อกำหนดเงื่อนไขและอาร์เรย์สตริงคงที่เพื่อกำหนดข้อความอาจทำให้เกิดปัญหาหาก enum และอาร์เรย์ไม่ซิงค์กัน การใช้แมโครเพื่อกำหนดคู่ทั้งหมด (enum, string) แล้วรวมถึงแมโครนั้นสองครั้งพร้อมกับคำจำกัดความที่เหมาะสมอื่น ๆ ในขอบเขตในแต่ละครั้งที่อนุญาตให้หนึ่งใส่ค่า enum แต่ละรายการถัดจากสตริง
supercat

2

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


ไม่ควรบันทึกมาโครหรือไม่
Casebash

@Casebash: แน่นอนแมโครควรมีการจัดทำเอกสารเหมือนกับซอร์สโค้ดอื่น ๆ ... แต่ในทางปฏิบัติแล้วฉันไม่ค่อยได้เห็นมันเลย
สกอตต์ดอร์แมน

3
เคยแก้ไขข้อบกพร่องเอกสารหรือไม่ มันไม่เพียงพอเมื่อจัดการกับรหัสที่เขียนไม่ดี
JeffO

OOP ก็มีปัญหาบางอย่างเช่นกัน ...
aoeu256

2

ให้เริ่มต้นด้วยการสังเกตว่า MACROs ใน C / C ++ นั้นมีข้อ จำกัด มากข้อผิดพลาดง่ายและไม่มีประโยชน์จริง ๆ

MACRO ที่ใช้งานใน LISP พูดหรือภาษาแอสเซมเบลอร์ z / OS สามารถเชื่อถือได้และมีประโยชน์อย่างเหลือเชื่อ

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

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