มาโครในโลกแห่งความจริงที่เลวร้ายที่สุดที่คุณเคยเจอเจอเคยทำมาก่อนคืออะไร?


176

มาโครในโลกแห่งความเป็นจริงที่เลวร้ายที่สุด คือการละเมิดที่คุณเคยเจอมาก่อน (โปรดอย่าตอบคำถาม IOCCC * haha ​​*)

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


ps: ฉันเคยใช้มาโครมาก่อน ... แต่โดยปกติฉันจะกำจัดมันในที่สุดเมื่อฉันมีวิธีแก้ปัญหา "ของจริง" (แม้ว่าวิธีการแก้ปัญหาจริงจะถูกแทรกเข้าไป


โบนัส:ยกตัวอย่างว่าแมโครนั้นดีกว่าโซลูชันที่ไม่ใช่มาโครจริงๆ

คำถามที่เกี่ยวข้อง: มาโคร C ++ จะมีประโยชน์เมื่อใด


+1 สำหรับการนำความสนใจไปที่การใช้อาละวาดอย่างรุนแรงฉันได้รับความเดือดร้อนจากมือของมาโคร
i_am_jorf

37
#define เท็จจริง // มีความสุขการแก้จุดบกพร่อง :)
n0rd

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

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

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

คำตอบ:


410

จากความทรงจำดูเหมือนว่า:

#define RETURN(result) return (result);}

int myfunction1(args) {
    int x = 0;
    // do something
    RETURN(x)

int myfunction2(args) {
    int y = 0;
    // do something
    RETURN(y)

int myfunction3(args) {
    int z = 0;
    // do something
    RETURN(z)

ใช่ถูกต้องไม่มีวงเล็บปิดในฟังก์ชันใด ๆ การเน้นไวยากรณ์เป็นเรื่องยุ่งดังนั้นเขาจึงใช้ vi เพื่อแก้ไข (ไม่ใช่กลุ่ม, มันมีการระบายสีไวยากรณ์!)

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

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


87
"คอมไพเลอร์พบข้อผิดพลาดในรหัสนี่คือการลงโทษ" !! บริษัท พบว่าคุณ ... ลงโทษพนักงานคนอื่น ๆ !
เรียนรู้

227
ในโซเวียตรัสเซียโปรแกรมรวบรวมคุณ!
Crashworks

53
เมื่อฉันอ่านเกี่ยวกับข้อผิดพลาด "การลงโทษ" ของคอมไพเลอร์สิ่งแรกที่ฉันคิดคือ "ด๊อบบี้ต้องรีดมือของเขา"
แกรมเพอร์โรว์

124
ฉันคิดว่าโปรแกรมเมอร์ (รวมอยู่ในตัวเอง) จะเหมาะกว่านี้ถ้าเราทุกคนทำ pushups 10 ครั้งทุกครั้งที่คอมไพเลอร์พบข้อผิดพลาดในรหัสของเรา สิ่งนี้อาจลดการเกิดขึ้นของการทดสอบโดยการคอมไพล์
MikeyB

5
หมอนั่นฟังดูยอดเยี่ยม แต่ใช่ฉันไม่เห็นว่าควรปรับปรุงขนาดรหัสอย่างไร
jalf

274

แย่ที่สุดของฉัน:

#define InterlockedIncrement(x) (x)++
#define InterlockedDecrement(x) (x)--

ฉันใช้เวลาสองวันในการติดตามชีวิตปัญหาการนับ COM แบบมัลติเธรดเนื่องจากคนงี่เง่าบางคนใส่มันลงในไฟล์ส่วนหัว ฉันจะไม่พูดถึง บริษัท ที่ฉันทำงานในเวลานั้น

คุณธรรมของเรื่องนี้? หากคุณไม่เข้าใจบางสิ่งให้อ่านเอกสารและเรียนรู้เกี่ยวกับมัน อย่าเพิ่งทำให้มันหายไป


146
@Joshua: หากคุณเรียกใช้รหัสนี้ในสภาพแวดล้อมแบบมัลติเธรดคุณอาจทำเช่นนั้นโดยไม่ได้ตั้งใจ
1800 ข้อมูล

11
"หากคุณไม่เข้าใจบางสิ่งให้อ่านเอกสารและเรียนรู้เกี่ยวกับมันอย่าเพิ่งทำให้มันหายไป" - อาเมน!
Paul Alexander

2
@ 1800 ข้อมูล: ฉันคิดว่าคุณจะเสียคะแนนซึ่งเป็นเหตุผลที่ฉันไม่สามารถให้คุณได้หนึ่ง p
wkf

5
ยกโทษให้ฉันในฐานะโปรแกรมเมอร์ที่ไม่ใช่ C ++: นี่เป็นปัญหาหลักที่ฟังก์ชั่น threadsafe ถูกแปลงเป็น non-threadsafe หรือไม่? หรือ InterlockedIncrement ต้องการตัวชี้ดังนั้นตอนนี้คุณจะเพิ่มตัวชี้แทนที่จะเป็นตัวชี้ หรือทั้งคู่?
Tim Pietzcker

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

166
#define ever (;;)
for ever { 
   ...
}

52
ฉันชอบ <#define ตลอดกาลสำหรับ (;;)> เพื่อให้คุณสามารถเขียน <ถาวร {... }>
paxdiablo

คนที่ผมไปโรงเรียนกับเครื่องหมายที่หายไปสำหรับสิ่งที่เคย ... เขาได้รับการสำลักที่มันเป็นในหนังสือข้อความ :-)
TofuBeer

6
ข้อเสนอแนะของ Pax ไม่ได้ส่งตรงจาก K&R ใช่ไหม ถึงกระนั้นก็ไม่คุ้มค่ากับความพยายามฉันจะบอกว่า
Jon Ericson

ที่จริงแล้วก็ไม่เลวเลย ฉันไม่ได้ใช้for (;;)สำนวนมิฉะนั้นฉันจะเพิ่มแมโครนี้ในรหัสของฉันทันที
AnT

1
@hayalci: ใน emacs lisp (และการใช้งาน lisp ทั่วไป) คุณสามารถทำได้(defmacro ever ())แล้ว(require 'cl (ever))
Joe D

145
#include <iostream>
#define System S s;s
#define public
#define static
#define void int
#define main(x) main()
struct F{void println(char* s){std::cout << s << std::endl;}};
struct S{F out;};

public static void main(String[] args) {
  System.out.println("Hello World!");
}

ถาม: ทุกคนสามารถทำได้โดยกำหนดและสร้างโครงสร้างให้น้อยลงหรือไม่ ;-)


19
คุณเพิ่งเขียนตัวแปลงจาวาเป็น c! horray!
Andreas Petersson

25
รายงานว่า "ไม่เหมาะสม" (I kid!)
Annika Backstrom

40
นั่นเป็นทั้งที่สวยงามน่าเกลียดหรือน่าเกลียดอย่างสวยงาม
คริสลัทซ์

38
@ Mark - มันประกาศpublicและstatic as nothing, void` เป็นintและmain(x)เป็นmain()จึงกลายเป็นpublic static void main(String[] args) int main()จากนั้นก็Systemจะกลายเป็นS s;sจึงSystem.out.println("Hello World!");กลายเป็นS s; s.out.println("Hello World!");ที่เรียกprintlnฟังก์ชั่นในFstruct ในSstruct
คริส Lutz

2
ลองดูที่นี้: mailcom.com/ioccc/chia/chia.c (ดาวน์โหลดและรวบรวมมัน)
โรแบร์โต Bonvallet

130
#define private public

ฉันเคยทำมาก่อน บางครั้งคุณเพียงแค่ต้องปรับเปลี่ยนตัวแปรสมาชิกหรือแทนที่ฟังก์ชั่นในรหัสของบุคคลที่สามที่คุณไม่สามารถเปลี่ยนแปลงได้ - และพวกเขาไม่ได้ให้ accessor ให้คุณ
Michael Kristofik

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

12
อืมมพฤติกรรมที่ไม่ได้กำหนดการละเมิดกฎข้อเดียวอย่างง่าย ใช่นี่คือผู้ชนะ
David Thornley

10
ด้วยสิ่งนั้นฉันสามารถเข้าถึงข้อมูลส่วนตัวและสาธารณะ แต่ไม่ได้รับการป้องกันและฉันไม่สามารถเข้าถึงสิ่งต่าง ๆ ระหว่างclassคำหลักและตัวแก้ไขการเข้าถึงครั้งแรก
Ken Bloom

3
@Ken:#define class struct #define protected public
Yakov Galka

107
#define if while

มันเป็นเรื่องตลกที่เล่นกับใครบางคนไม่พบว่ามีผู้ได้รับผลกระทบ


22
#define แม้ว่าจะร้ายกาจยิ่งขึ้นไปอีก
starblue

7
เราควรชี้แจงข้อความของคุณให้ชัดเจน มันก็ไม่ได้พบขบขันโดยคนที่ได้รับผลกระทบ :-)
Andrew Shepherd

6
เมื่อฉันทำการบ้านฉันมักทำสิ่งต่าง ๆ ตามจุดประสงค์เพื่อรบกวนครู
pyon

15
นี่เป็นการเล่นตลกที่ดี แต่มันจะไม่คอมไพล์ถ้ามีคำสั่ง "else" ใด ๆ ฉันพบว่า #define if (x) if (true) มีประสิทธิภาพมากที่สุด
กราฟิก Noob

32
ฉันมักจะชอบ #define sizeof (x) rand ()
Jon

106

น่าเกลียด:

#define begin {
#define end }
/* and so on */

อย่างจริงจังถ้าคุณต้องการรหัสในภาษาปาสคาลซื้อคอมไพเลอร์ภาษาปาสคาลอย่าทำลายภาษา C ที่สวยงาม


45
ตอนนี้คุณทำให้ฉันสงสัยว่าภาษาใดที่ฉันสามารถจำลองด้วยไฟล์ส่วนหัวที่ฉลาดพอ
บิล Lizard

47
C ไม่สวยงาม มันค่อนข้างน่าเกลียด
rlbond

27
ความงามของมันอยู่ในความเรียบง่าย มันบอกว่ามันมีความเร็วของภาษาแอสเซมบลีรวมกับความสามารถในการอ่านของ ... แอสเซมบลีภาษา :-) ฉันชอบมันมากกว่า C ++ ป่อง (แม้ว่าฉันจะชอบ Java ในงานประจำวันของฉันเนื่องจากห้องสมุดขนาดใหญ่)
paxdiablo

9
ไม่มีจริงๆ. ค้นหาแหล่งต้นฉบับของ Bourne สำหรับเชลล์ bourne เขาทำสิ่งนี้อย่างแน่นอนเพื่อรับความยุ่งเหยิงแบบ ALGOL
RBerteig

3
#define DO for (int _i = 0; _i <= 1; ++ _ i) {ถ้า (_i == 1) //// LINE BREAK //// #define IF (cond); ถ้า (! (cond)) แตก; } //// LINE BREAK //// DO printf ("a") IF (1 == 2);
Adrian Panasiuk

93

'สถาปนิก' คนที่ถ่อมตนมากคุณรู้จักประเภทนี้มีดังต่อไปนี้:

#define retrun return

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


ฉันพิมพ์ผิดมากจนฉันคิดว่าจริง
Joshua

4
ค่อนข้างจะสอนให้ผู้แก้ไขของคุณทำการทดสอบซ้ำโดยอัตโนมัติ Ive ทำ hackeries ดังกล่าวไปยัง IRC-ลูกค้าของฉันอย่างน้อย
Tetha

1
เฮ้ฉันคิดว่าฉันเคยทำงานกับ 'สถาปนิก' คนนั้นด้วย ในที่สุดเขาก็ถูกจัดประเภทใหม่สถาปนิกอาวุโสเมื่อเขาต้องการที่จะอัตตาของเขา
BIBD

1
ฉันกำหนด 'rn' ใหม่เป็น 'rm' ใน bash เนื่องจากฉันไม่สามารถพิมพ์ได้และผู้อ่าน 'rn' ใช้เวลา 5 นาทีในการเริ่มต้นและเชื่อมต่อกับเซิร์ฟเวอร์
Martin Beckett

2
คุณไม่สามารถเปิดเทอร์มินัลใหม่ (หรือเปลี่ยนไปใช้ vt อื่น) และทำkillall rnอย่างไร
Joe D

69

โลกแห่งความจริง? MSVC มีมาโครใน minmax.h เรียกmaxและminทำให้เกิดข้อผิดพลาดของคอมไพเลอร์ทุกครั้งที่ฉันตั้งใจจะใช้std::numeric_limits<T>::max()ฟังก์ชั่นมาตรฐาน


2
อ่าใช่ว่าเป็นเหตุผลที่ผมมีส่วนหัวพิเศษที่มีสุขภาพจิตดีคืน # undef หลังจากคน MS-เฉพาะ ...
พอนทัส Gagge

3
แก้ไขด้วย (std :: numeric_limits <T> :: max) () แต่ใช่น่ารำคาญทีเดียว
rlbond

36
เพิ่ม NOMINMAX ให้กับคุณสมบัติโครงการของคุณภายใต้ C / C ++ -> Preprocessor -> ข้อกำหนดของตัวประมวลผลล่วงหน้า
mattnewport

18
มาโครเหล่านี้มีอยู่ในส่วนหัวของ MS นานกว่านาทีและสูงสุดอยู่ในไลบรารีมาตรฐาน C ++
ริชาร์ด

4
มันยิ่งเลวร้ายลงเมื่อการพึ่งพาจากภายนอกอื่น ๆ สี่ครั้งของคุณกำหนด min / max ของตัวเองในระดับที่แตกต่างกันของ suckiness ตั้งแต่มาโครที่มีวงเล็บไม่ดีไปจนถึงเทมเพลตที่เขียนได้ดีและหนึ่งในนั้นต้องทำให้เป็นไปไม่ได้ หรือข้ามสิ่งเหล่านี้ ... ในหนังสือของฉันภาษาคือ 50% ที่จะกล่าวโทษ
Roman Starkov

58

การผสมผสานระหว่างไวยากรณ์ภาษาปาสคาลและคำหลักภาษาฝรั่งเศส:

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }

36
#define zut_alors exit (-1)
MikeyB

4
มันยอดเยี่ยมมากและทำให้ฉันหัวเราะออกมาดัง ๆ ดังนั้นนี่เป็นพื้นฐานของเวอร์ชันภาษาฝรั่งเศสพื้นฐานของภาษาฝรั่งเศสที่ใช้ใน C?
Bobby

56

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

ADDRESS alloc(nbytes)
    POS     nbytes;
{
    REG POS rbytes = round(nbytes+BYTESPERWORD,BYTESPERWORD);

    LOOP    INT     c=0;
    REG BLKPTR  p = blokp;
    REG BLKPTR  q;
    REP IF !busy(p)
        THEN    WHILE !busy(q = p->word) DO p->word = q->word OD
        IF ADR(q)-ADR(p) >= rbytes
        THEN    blokp = BLK(ADR(p)+rbytes);
            IF q > blokp
            THEN    blokp->word = p->word;
            FI
            p->word=BLK(Rcheat(blokp)|BUSY);
            return(ADR(p+1));
        FI
        FI
        q = p; p = BLK(Rcheat(p->word)&~BUSY);
    PER p>q ORF (c++)==0 DONE
    addblok(rbytes);
    POOL
}

2
สองจุด: หนึ่งจุดนี้ทำให้การเยื้องของข้อความต้นฉบับยุ่งเหยิง และสองรหัสดูดีสำหรับสิ่งที่มันเป็น: 1970s Unix C โดยแฟน Algol-68 ที่เร่าร้อน ถ้า _ ผู้โชคดีแข็งทื่อสามารถแสดงตัวตนในสไตล์แปลก ๆ ทำไม Steve Bourne ถึงไม่ได้? แน่นอนว่ามีคนกล่าวโทษผู้ที่ไม่ทราบว่าอัลกอล 68 อาจไม่ชื่นชมโอกาสที่จะขยายรสนิยมของพวกเขาเอง
Darius Bacon

ฉันคิดว่านี่อาจเป็นเรื่องตลกของ Steve Bourne มากกว่ารูปแบบการเขียนโปรแกรมที่แนะนำ
Martin Beckett

2
ฉันเคยเห็นif... else... elif... fiและcase... esacก่อนหน้านี้ (ในภาษาที่บอร์นคิดค้นขึ้นมาสำหรับ sh) แต่loop... poolเป็นอัญมณีจริง
ฮอบส์

54

ฉันต้องการส่งสำหรับการประกวดอัญมณีที่มีชื่อว่าchaos-ppซึ่งใช้ภาษาที่ใช้งานได้โดยใช้มาโครตัวประมวลผลก่อน

ตัวอย่างหนึ่งคือการคำนวณหมายเลขฟีโบนักชีที่ 500 ทั้งหมดโดยผู้ประมวลผลล่วงหน้า:

รหัสต้นฉบับก่อนตัวประมวลผลล่วงหน้าจะมีลักษณะดังนี้:

int main(void) {
   printf
     ("The 500th Fibonacci number is "
      ORDER_PP(8stringize(8to_lit(8fib(8nat(5,0,0)))))
      ".\n");
   return 0;
}

การประมวลผลไฟล์ล่วงหน้าเราได้รับผลลัพธ์ต่อไปนี้ (หลังจากรอค่อนข้างนาน):

$ cpp -I../inc fibonacci.c 2>/dev/null | tail
  return fib_iter(n, 0, 1);
}
# 63 "fibonacci.c"
int main(void) {
   printf
     ("The 500th Fibonacci number is "
      "139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125"
      ".\n");
   return 0;
}

1
คุณสามารถคว้ารหัสจาก CVS และดู ฉันได้ใส่รายละเอียดเพิ่มเติมเกี่ยวกับเรื่องนี้ในบล็อกของฉันเมื่อไม่นานมานี้เมื่อฉันสะดุด: bnpcs.blogspot.com/2009/02/ ถ้าไม่ได้มีปัญหาสำหรับการแก้จุดบกพร่องรหัสผลลัพธ์ (ปัญหาของการมีสายยาวมากถ้า พวกเขาจะถูกสร้างโดยเช่น "ภาษา") ก็จะได้รับการใช้งานได้แม้ในขณะที่ปฏิบัติรหัสเครื่องกำเนิดไฟฟ้าสำหรับซี
แอนดรู Y

ฉันสามารถจินตนาการได้ว่ามันจะใช้เวลานานในการรวบรวม
Paul Fultz II

52

โดยตรงจาก Qt:

#define slots   /* */
#define signals /* */

ดีจริง ๆ ที่ได้โต้ตอบกับ libs อื่น ๆ เช่น boost :: signal ... เพียงแค่ตัวอย่างมีคนอื่น ๆ ใน Qt ที่สร้างรหัสที่ดูตลกเช่น:

class X : public QObject {
   Q_OBJECT
private slots:
   //...
public signals:
   //...
};

และนั่นคือ C ++ ... แต่ทันใดนั้น:

boost::signals::trackable

ไม่ถูกต้อง C ++ อีกต่อไป


5
:) ดังนั้นมันเป็นมาโครที่ทำลายไลบรารี่อื่น ๆ ดียิ่งกว่าที่ฉันคาดไว้ :)
David Rodríguez - dribeas

38
Qt เป็นดินแดนมากและเลวทรามต่ำช้าจะโจมตีห้องสมุดอื่น ๆ ที่มีความพยายามที่จะครอบครอง namespace ของ :)
Jeremy Friesner

21
Sadly Qt โจมตีห้องสมุดนอก namespace ด้วยการใช้ macros
David Rodríguez - dribeas

7
โชคดีที่เพิ่ม :: signals2 ได้รับการแก้ไขปัญหานี้;)
bdonlan

9
ใช้ Q_SIGNALS และ Q_SLOTS หากคุณกลัวการโต้ตอบนี้
Tadeusz A. Kadłubowski

50

Windows.h มีฟังก์ชั่นมากมายที่ใช้งานมาโครในทางที่ผิด


MrValdez รำคาญแมโครแมโคร GetObject ที่พบใน Windows.h

แมโคร GetObject เปลี่ยนฟังก์ชัน GetObject () เป็น GetObjectA () หรือ GetObjectW () (ขึ้นอยู่กับว่าบิลด์คอมไพล์ถูกคอมไพล์ใน non-unicode และ unicode ตามลำดับ)

MrValdez ไม่ชอบทำอะไรก่อนฟังก์ชั่น GetObject

#undef GetObject

Object *GetObject()

ทางเลือกคือเปลี่ยนชื่อฟังก์ชันเป็นอย่างอื่นเช่น GetGameObject ()


jdkoftinoff ในความคิดเห็นได้ถูกตอกตะปู: ปัญหาคือฟังก์ชั่น windows API ทั้งหมดเป็นมาโคร

Adam Rosenfield กล่าวว่าปัญหาสามารถแก้ไขได้ด้วยการกำหนด NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX ฯลฯ ก่อนที่จะรวม windows.h เพื่อลบปัญหา


3
คุณสามารถระงับสิ่งนี้ได้ แต่ # define'ing NOGDI ก่อนที่จะรวม windows.h ซึ่งแน่นอนว่าคุณไม่จำเป็นต้องใช้ฟังก์ชัน GDI ต่างๆ มีมาโครอื่น ๆ อีกมากมายเช่น WIN32_LEAN_AND_MEAN, NOMINMAX เป็นต้นซึ่งจะป้องกันสิ่งอื่น ๆ จากการถูกกำหนดหรือรวมไว้
Adam Rosenfield

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

1
มันค่อนข้างน่ารำคาญที่ win32 มีมาโครทั้งหมดในการแปลงชื่อ API เป็น FooA และ FooW เรามีปัญหากับ SendMessage
i_am_jorf

6
ปัญหาคือฟังก์ชั่น windows API ทั้งหมดเป็นมาโคร บิตหนึ่งที่ฉันคือ GetTickCount () เนื่องจากฉันทำส่วนใหญ่ของการเขียนโปรแกรมของฉันนอก windows ฉันพบกำหนดทั้งหมดในส่วนหัวของ windows และจากนั้นทำของตัวเองรวมไฟล์ที่กำหนดไว้ทั้งหมดเพื่อตรวจสอบความเข้ากันได้ก่อน
jdkoftinoff

12
ฉันคิดว่าเรามีผู้ชนะ มันเป็นโลกแห่งความจริงมันเป็นความคิดที่ไม่ดีอย่างน่าขันและมันก็ส่งผลกระทบต่อโปรแกรมเมอร์ผู้บริสุทธิ์จำนวนมาก ใครก็ตามที่รับผิดชอบอัญมณีนี้ที่ Microsoft ถือว่าเป็นอาชญากรสงครามส่วนที่ดีที่สุดคือ Microsoft ไม่คิดว่าจะใช้ชื่อสามัญที่น่าอัศจรรย์เช่น GetObject, SendMessage หรือ CreateWindow
jalf

45
#define return if (std::random(1000) < 2) throw std::exception(); else return

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


4
เพิ่งทดสอบอันนี้อย่างน้อยก็ไม่ได้รวบรวมโดยค่าเริ่มต้นเพราะไม่มีการรวมสำหรับการสุ่มและมันก็เป็นสีแดง - squiggled แล้ว หากคุณมีการรวมโดยไม่ได้ตั้งใจสิ่งต่าง ๆ แย่ลง - VC ++ 2010 ทำเครื่องหมายว่ามันเป็นคำหลักและไม่แสดงคำแนะนำการขยายตัวของแมโครดังนั้นจึงไม่มีความช่วยเหลือจาก IDE ในการค้นหาสิ่งนี้: - /
OregonGhost

ฉันรักมัน! อัจฉริยะบริสุทธิ์ ลองนึกภาพว่าคุณจะดูดีแค่ไหนเมื่อคุณ "Debug" แอปพลิเคชันนี้เมื่อไม่มีใครจัดการได้
brice

36

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

ไม่จำเป็นต้องบอกว่ามันถูกปรับปรุงใหม่และไม่ได้ใช้ในฐานรหัสของเราอีกต่อไป

อย่าถูกโยนออกโดยคำหลักที่เน้นสี นี่คือแมโครทั้งหมด

#define DECLARE_MODIFICATION_REQUEST_PACKET( T )                                                \
namespace NameSpace                                                                     \
{                                                                                       \
                                                                                        \
class T##ElementModificationRequestPacket;                                                          \
}                                                                                       \
                                                                                        \
DECLARE_STREAMING_TEMPLATES( IMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase )    \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( NameSpace::ElementModificationRequestPacket<T> )     \
DECLARE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )      \
                                                                                        \
namespace NameSpace {                                                                   \
class DLLIMPEXP_COMMON T##ModificationRequestPacket : public ElementModificationRequestPacket<T>\
{                                                                                       \
public:                                                                                 \
    T##ModificationRequestPacket( NetBase * pParent )                                   \
    : ElementModificationRequestPacket<T>( pParent ), m_Gen() {}                            \
                                                                                        \
    T##ModificationRequestPacket( NetBase * pParent,                                    \
                            Action          eAction,                                    \
                            const T &   rT )                                            \
    : ElementModificationRequestPacket<T>( pParent, eAction, rT ), m_Gen() {}               \
                                                                                        \
    T##ModificationRequestPacket( const T##ModificationRequestPacket & rhs )                        \
    : ElementModificationRequestPacket<T>( rhs ), m_Gen() {}                                \
                                                                                        \
    virtual                     ~T##ModificationRequestPacket( void ) {}                        \
                                                                                        \
    virtual Uint32          GetPacketTypeID( void ) const                           \
    {                                                                                   \
        return Net::T##_Modification_REQUEST_PACKET;                                        \
    }                                                                                   \
                                                                                        \
    virtual OtherNameSpace::ClassID GetClassID ( void ) const                           \
    {                                                                                   \
        return OtherNameSpace::NetBase::GenerateHeader( OtherNameSpace::ID__LICENSING,  \
                                                         Net::T##_Modification_REQUEST_PACKET );    \
    }                                                                                   \
                                                                                        \
    virtual T##ModificationRequestPacket * Create( void ) const                             \
    { return new T##ModificationRequestPacket( m_pParent ); }                                   \
                                                                                        \
    T##ModificationRequestPacket() {}                                                           \
                                                                                        \
protected:                                                                              \
    OtherNameSpace::ObjectAutogeneration<T##ModificationRequestPacket> m_Gen;                       \
                                                                                        \
    friend class OtherNameSpace::StreamingBase::StreamingClassInfoT<T##ModificationRequestPacket >;                     \
    OtherNameSpace::StreamingBase::Streaming<T##ModificationRequestPacket, ElementModificationRequestPacket<T> >    m_Stream;   \
                                                                                        \
};                                                                                      \
}                                                                                       \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )            \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )            \
typedef  ThirdNameSpace::BroadcasterT<const T##ModificationRequestPacket>  T##ModifiedBroadcaster;



#define IMPLEMENT_MODIFICATION_REQUEST_PACKET( T )                                                                  \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( NameSpace::ElementModificationRequestPacket<T> )                         \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )        \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )        \
INSTANTIATE_STREAMING_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase ) \
INSTANTIATE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )

อัปเดต (17 ธันวาคม 2552):

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


3
เห็นได้ชัดว่าเขาไม่เคยได้ยิน: "การดีบักนั้นยากกว่าการเขียนรหัสสองเท่าในตอนแรกดังนั้นหากคุณเขียนรหัสอย่างชาญฉลาดที่สุดเท่าที่จะทำได้คุณเป็นผู้นิยามไม่ฉลาดพอที่จะทำการแก้ไข" -Brian W. Kernighan
Trevor Boyd Smith

33

ฉันทำสิ่งต่อไปนี้ด้วยตัวเองและฉันคิดว่าฉันได้เรียนรู้อะไรบางอย่างจากมัน

ในปี 1992 หรือดังนั้นฉันจึงเขียนล่ามเสียงกระเพื่อมขนาดเล็ก มันไม่ได้นำมาใช้ใน C ปกติ แต่เป็นภาษา C ที่ตีความ ภาษาที่เหมือน C นี้ใช้ตัวประมวลผลล่วงหน้า C มาตรฐาน

Lisp interpreter แน่นอนมีฟังก์ชั่นรถยนต์ซึ่งใช้ใน Lisp เพื่อส่งคืนองค์ประกอบแรกในรายการและcdrซึ่งส่งคืนส่วนที่เหลือของรายการ พวกเขาใช้งานเช่นนี้:

LISPID car(LISPID id) {
    CHECK_CONS("car", 1, id);
    return cons_cars[id - CONS_OFFSET];
} /* car */

LISPID cdr(LISPID id) {
    CHECK_CONS("cdr", 1, id);
    return cons_cdrs[id - CONS_OFFSET];
} /* cdr */

(ข้อมูลถูกเก็บไว้ในอาร์เรย์เนื่องจากไม่มี structs CONS_OFFSETเป็นค่าคงที่ 1,000)

carและcdrถูกใช้บ่อยใน Lisp และสั้นและเนื่องจากการเรียกใช้ฟังก์ชั่นไม่ได้รวดเร็วมากในภาษาที่ใช้งานฉันจึงปรับโค้ดของฉันให้ดีขึ้นโดยการใช้ฟังก์ชั่น Lisp ทั้งสองเป็นแมโคร:

#define car(id) (CHECK_CONS("car", 1, (id)), cons_cars[(id) - CONS_OFFSET])
#define cdr(id) (CHECK_CONS("car", 1, (id)), cons_cdrs[(id) - CONS_OFFSET])

CHECK_CONSตรวจสอบว่าข้อโต้แย้งของจริงเป็นรายการและเนื่องจากมีการใช้บ่อยในล่ามและสั้นฉันจึงเขียนว่าเป็นแมโคร:

#define CHECK_CONS(fun, pos, arg)   \
    (!IS_CONS(arg) ?        \
        LISP_ERROR("Arg " + pos + " to " + fun +    \
                   " must be a list: " + lispid2string(arg)) : 0)

IS_CONSและLISP_ERRORก็ใช้บ่อยเช่นกันดังนั้นฉันทำให้มันเป็นมาโครเช่นกัน:

#define IS_CONS(id) \
    (   intp(id) && (id) >= CONS_OFFSET     \
     && ((id) - CONS_OFFSET) < sizeof(cons_cars))

#define LISP_ERROR(str)     (throw((str) + "\n"))

ดูเหมือนจะสมเหตุสมผลหรือไม่

แต่ทำไมระบบทั้งหมดจึงล้มเหลวในบรรทัดนี้:

id2 = car(car(car(car((id1))));

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

id2 = ((!(intp( (((!(intp( (((!(intp( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
&& ( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) && ( (((!(intp(
(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) >= 1000 && ((
(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (((!(intp( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1))
&& ( (id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars))

18
I optimized my code by implementing those [..] functions as macros- คำพูดสุดท้ายที่โด่งดัง ...
BlueRaja - Danny Pflughoeft

3
ฉันกระทำการละเมิดที่คล้ายกันในล่ามรุ่นแรกของฉัน ผลักดันและป๊อปมีฟังก์ชั่นที่มีความสำคัญเพื่อที่ว่าพวกเขาควรจะแมโคร แต่การเขียนนิพจน์ที่เกี่ยวข้องกับสิ่งเหล่านี้มากกว่าหนึ่งรายการทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด พฤติกรรมที่ไม่ได้กำหนดจะถูกจับเมื่อรวบรวมที่ -O3 และที่ -O3 รุ่นฟังก์ชั่นน่าจะถูกแทรกไว้แล้ว
luser droog

29

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

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

#define I  Any void_me
#define thou  Any void_thee
#define iam(klas)  klas me = (klas) void_me
#define thouart(klas)  klas thee = (klas) void_thee
#define my  me ->
#define thy  thee ->
#define his  him ->
#define our  my methods ->
#define your  thy methods ->

... ซึ่งเขาเคยเขียน monstrosities ดังนี้:

void Thing_setName (I, const char *name) {
iam (Thing);
if (name != my name) {
    Melder_free (my name);
    my name = Melder_wcsdup (name);
    }
    our nameChanged (me);
}

void Thing_overrideClass (I, void *klas) {
iam (Thing);
my methods = (Thing_Table)klas;
if (! ((Thing_Table) klas) -> destroy)
    ((Thing_Table) klas) -> _initialize (klas);
}

โครงการทั้งหมด (~ 60,000 LOC) เขียนในรูปแบบที่คล้ายกัน - มาร์โกนรกชื่อแปลก ๆ ศัพท์ภาษาอังกฤษ - ภาษาอังกฤษเป็นต้นโชคดีที่เราสามารถโยนรหัสออกมาได้เนื่องจากฉันพบห้องสมุด OSS ซึ่งมีอัลกอริทึมเดียวกันหลายสิบ เร็วกว่า

(ฉันได้คัดลอกและแก้ไขคำตอบนี้ซึ่งฉันทำไว้กับคำถามนี้แล้ว )


3
ฉันค่อนข้างหลงใหลในความเป็นเจ้าของและอังกฤษโบราณเพราะทุกอย่างฉันเห็นด้วยว่าโค้ดดูแย่มาก
Darius Bacon

27

สิ่งที่แย่ที่สุดที่ฉันเคยพบคือในผลิตภัณฑ์ที่มีชุดโปรแกรมปฏิบัติการซึ่งผู้นำทางเทคนิคที่กำหนดไม่ได้คิดหาไลบรารี่

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

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

เขาใช้ #ifdef แทน

   void DisplayLoadError()
   {
   #if defined __TIMETABLE_EDITOR
   MessageBox("Timetable Editor failed to load the correct timetable", MB_ERROR);
   #else if defined __SCHEDULESET_EDITOR
   MessageBox("Schedule Set Editor faied to load the correct Schedule Set", MB_ERROR);
   #else if defined __ROSTER_EDITOR
   MessageBox("Roster Editor failed to load the correct Roster", MB_ERROR);
   #endif
   }

17

การใช้ตัวประมวลผลล่วงหน้า LINE เพื่อสร้าง ID เฉพาะสำหรับข้อความที่ส่งผ่านเครือข่าย:

NetworkMessages.h

#define MSG_LOGIN  __LINE__
#define MSG_LOGOUT __LINE__
#define MSG_CHAT   __LINE__

นี่คือตัวอย่างที่แมโครดีกว่าโซลูชันที่ไม่ใช่แมโคร:

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

นอกจากนี้การเพิ่มข้อความใหม่ทำได้ง่ายขึ้นเพียงแค่เพิ่มข้อความลงในแหล่งที่มา

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


8
และเวอร์ชันอาจเข้ากันไม่ได้ (ไม่ดี!) ทำไม Enum ถึงไม่พอเพียง?
แปลกหน้า

ทั้งนี้และ Enum มีปัญหาความไม่ลงรอยกันเหมือนกัน
MrValdez

17
ตอนนี้ฉันมาและเรียงลำดับ #defines ... และการเปลี่ยนแปลงโปรโตคอล หรือฉันจะได้รับศาสนา Doxygen และจัดทำเอกสารรหัสข้อความทั้งหมดและโปรโตคอลเปลี่ยนไป อย่างน้อย Enum จะเสถียรภายใต้การเปลี่ยนแปลงหลัง
RBerteig

3
@MrValdez มีข้อ จำกัด น้อยกว่าในการเก็บบล็อกของ enums ตามลำดับมากกว่าที่จะให้คำจำกัดความในบรรทัดเดียวกันเมื่อเทียบกับไฟล์เริ่มต้น
peterchen

ฉันรู้ว่านี่เป็นโพสต์เก่า แต่มันใช้งานได้ดีไหม ผมหมายถึง #define ก็จะเปลี่ยนคงข้อความไปยังสายและเพียงแล้วสายจะขยายไปยังหมายเลขบรรทัดดังนั้นทุกครั้งที่เราใช้อย่างต่อเนื่องเช่นเดียวกันกับเส้นที่แตกต่างกัน - มันจะเปลี่ยนไป (ไปยังหมายเลขบรรทัดปัจจุบัน)?
XzKto

16

ตัวอย่างหนึ่งที่ไม่ดีพอสมควร:

#ifdef __cplusplus
#define class _vclass
#endif

สิ่งนี้อนุญาตให้โครงสร้าง C ที่มีตัวแปรสมาชิกถูกเรียกclassให้จัดการโดยคอมไพเลอร์ C ++ มีสองหัวที่มีโครงสร้างนี้อยู่ หนึ่งในนั้นยังมี '#undef class' ในตอนท้ายและอีกอันหนึ่งไม่มี


1
นี่คือเหตุผลที่ Objective-C ใช้แทน@class class

14

ในหนึ่งปีของการแข่งขัน C International Obfuscated C Coding มีรายการที่โปรแกรมทั้งหมดคือ:

P

ด้วยเงื่อนไขที่คุณสามารถกำหนดPใน makefile ให้เป็นโปรแกรมที่คุณต้องการ

เมื่อฉันจำได้ว่ามันชนะในประเภทใดประเภทหนึ่งและในปีต่อมามีกฎหนึ่งที่ไม่อนุญาตให้เข้าร่วมในรูปแบบดังกล่าว

(แก้ไข: หกเดือนต่อมาหรืออะไรบางอย่าง ... ฉันแน่ใจว่าสิ่งที่ "ไม่ IOCCC" ไม่ได้อยู่ในคำถามหลักเมื่อฉันเขียนสิ่งนี้ ... )


12

ฉันเบื่อวันหนึ่งและเล่นกับบล็อกใน Objective-C ...

#define Lambda(var, body) [^ id(id (var)) { return (body);} copy]
#define Call(f, arg) ((id(^)(id))(f))(arg)
#define Int(num) [NSNumber numberWithInteger:(num)]
#define Mult(a, b) Int([(a) integerValue] * [(b) integerValue])
#define Add(a, b) Int([(a) integerValue] + [(b) integerValue])
#define Sub1(n) Int([(n) integerValue] - 1)
#define Add1(n) Int([(n) integerValue] + 1)
#define If(cond, thenblock, elseblock) ([(cond) integerValue] ? (thenblock) : (elseblock))
#define Cons(car, cdr_) [[ConsType alloc] initWithCar:(car) cdr:(cdr_)]
#define Car(list) [(list) car]
#define Cdr(list) [(list) cdr]
#define Define(var, value) id var = (value)
#define Nullq(value) Int(value == nil)

ช่วยให้สิ่งที่ "น่าสนใจ" เช่น:

Define(Y, Lambda(f, Call(Lambda(x, Call(x, x)),
                         Lambda(x, Call(f, Lambda(y, Call(Call(x, x), y)))))));
Define(AlmostTotal, Lambda(f, Lambda(list, If(Nullq(list), Int(0),
                                              Add(Car(list), Call(f, Cdr(list)))))));
Define(Total, Call(Y, AlmostTotal));
Print(Call(Total, Cons(Int(4), Cons(Int(5), Cons(Int(8), nil)))));

(ฟังก์ชั่นบางอย่างและคำจำกัดความของชั้นเรียนไม่แสดงเพื่อความกะทัดรัด)


"ผมเบื่อวันหนึ่ง" ที่มีชื่อเสียงนักพัฒนาคำพูดสุดท้าย :)
ริชาร์ดเจรอสส์ที่สาม

11

สิ่งที่แย่ที่สุดที่ฉันเห็นคือไม่ใช่ :-)

มีคนเขียน strcpy (ฉันคิดว่ามันเป็น ... มากกว่า 10 ปีที่แล้ว) ฟังก์ชั่นด้านในของวิธีการ (เพราะพวกเขาไม่ต้องการค่าใช้จ่ายในการโทร strcpy ... ถอนหายใจ)

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

รหัสคือบันทึกที่เหมือนกันสำหรับประเภท (ดังนั้นควรใช้มาโคร)

แน่นอนว่า strcpy ที่พวกเขาเขียนนั้นช้ากว่าแอสเซมเบลอร์มือที่อยู่ในไลบรารีมาตรฐานมาก ...

แน่นอนว่าถ้าพวกเขาทำมันทั้งหมดเป็นมาโครมันอาจถูกแทนที่ด้วยการเรียก strcpy ...

แน่นอนฉันลาออกจาก บริษัท (ไม่ใช่โดยตรงเพราะนั้น ... )


The code was identical save for the types (so should have used a macro).ไม่เขาควรใช้เทมเพลต
BlueRaja - Danny Pflughoeft

1
เขาควรจะใช้สิ่งที่มีอยู่ใน strcpy! (และมันก็คือรหัส C ไม่ใช่ C ++ ดังนั้นจึงไม่มีเทมเพลต) :-P
TofuBeer

การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นรากฐานของความชั่วร้ายทั้งหมด
Hubert Kario

11

ข้อผูกพัน

#define FOR  for

และ

#define ONE  1
#define TWO  2
...

ใครจะรู้


5
แต่ - แต่ - แต่ไม่มีบทบัญญัติในรหัส! ;)
เบอร์นาร์ด

พวกเขายังคงเป็นตัวอักษรจันทร์ควรตั้งชื่อตามวัตถุประสงค์ / เจตนาไม่ใช่สัญลักษณ์สำรอง รหัส COBOL ผมได้ยินเกี่ยวกับพวกเขาทำตัวแปร 5 = 5 จากนั้นก็มีรหัสบอกชุด 5 = 10 ... คนที่แปลกใจจริงเมื่อพวกเขาทำ var + 5 และได้ var + 10
เกร็ก Domjan

1
ไม่เคยได้ยินเรื่องนี้กับ COBOL เฉพาะกับ FORTRAN แน่นอน COBOL มี ZERO, ZEROS และ ZEROES เป็นคำสงวนซึ่งทั้งหมดนี้มีความหมายเหมือนกับ 0
David Thornley

ดีกว่า "#define ONE 0" มาก หากคุณต้องการหัวเราะคิกคักให้ค้นหาเว็บนั้นและต้องประหลาดใจด้วยจำนวนครั้งที่ไม่เป็นศูนย์
เปิดใหม่

11
#define TRUE 0 // dumbass

คนที่ทำสิ่งนี้อธิบายตัวเองหลายปีต่อมา - ฟังก์ชั่นห้องสมุด C ส่วนใหญ่ (ถ้าไม่ใช่ทั้งหมด) จะคืนค่า 0 เป็นตัวบ่งชี้ว่าทุกอย่างเป็นไปด้วยดี ดังนั้นเขาต้องการที่จะสามารถเขียนโค้ดเช่น:

if (memcpy(buffer, packet, BUFFER_SIZE) == TRUE) {
; // rape that packet
}

ไม่จำเป็นต้องพูดว่าไม่มีใครในทีมของเรา (ผู้ทดสอบหรือผู้พัฒนา) กล้าที่จะมองรหัสของเขาอีกครั้ง


1
ฉันตำหนิฟังก์ชันไลบรารี C สำหรับการทำให้ 0 "ทุกอย่างเรียบร้อย": P
RCIX

6
ทำไมไม่ประกาศบางอย่างเช่น#define FLAG_SUCCESS 0?
pyon

11

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

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}

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

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

10
#include <iostream>
#define public_static_void_main(x) int main()
#define System_out_println(x) std::cout << x << std::endl

public_static_void_main(String[] args) {
  System_out_println("Hello World!");
}

3
และคุณต้องการที่จะเขียนรันไทม์ ดูเวลาที่ฉันบันทึกไว้!
เบอร์นาร์ด

4
@Trevor: ใช่ ... คนฉลาดยังคงทำ Java อยู่ วิ่งเพื่อปก
Michael Myers

หากคุณใส่ [] หลังจาก args แทนที่จะเป็นก่อนหน้านี้และ "#define String int argc, char *" มันจะคอมไพล์ (เศร้า)
Adam Rosenfield

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

10

โดยเพื่อนร่วมชั้นที่ไม่เข้าใจกฏเกี่ยวกับตัวเลขเวทย์:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1


9

ASA - http://www.ingber.com/#ASA

คุณต้องดาวน์โหลดเพื่อซาบซึ้ง กระบวนการทำงานทั้งหมดถูกกำหนดโดยมาโคร มันอ่านไม่ได้อย่างสมบูรณ์ ตัวอย่างเช่น -

 if (asa_open == FALSE) {
asa_open = TRUE;
++number_asa_open;
#if ASA_PRINT
if (number_asa_open == 1) {
  /* open the output file */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
#else
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "w");
#endif
  }
#else /* USER_ASA_OUT */
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (ASA_OUT, "a");
#else
    ptr_asa_out = fopen (ASA_OUT, "w");
#endif
  }
#endif /* USER_ASA_OUT */
} else {
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
  fprintf (ptr_asa_out, "\n\n\t\t number_asa_open = %d\n",
           number_asa_open);
}
#endif /* ASA_PRINT */
} else {
++recursive_asa_open;
#if ASA_PRINT
if (recursive_asa_open == 1) {
  /* open the output file */
#if ASA_SAVE
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
#else /* ASA_SAVE */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {

เป็นต้น

และนั่นเป็นเพียงการตั้งค่าตัวเลือก โปรแกรมทั้งหมดเป็นเช่นนั้น


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