Apa penyalahgunaan makro / pra-prosesor terburuk di dunia nyata yang pernah Anda temui?

176

Apa penyalahgunaan makro / pra-prosesor terburuk di dunia nyata yang pernah Anda temui (tolong jangan buat jawaban IOCCC * haha ​​*)?

Harap tambahkan cuplikan atau cerita pendek jika benar-benar menghibur. Tujuannya adalah untuk mengajarkan sesuatu alih-alih selalu memberi tahu orang-orang "jangan pernah menggunakan makro".


ps: Saya pernah menggunakan makro sebelumnya ... tapi biasanya saya menyingkirkannya pada akhirnya ketika saya memiliki solusi "nyata" (bahkan jika solusi sebenarnya diuraikan sehingga menjadi mirip dengan makro).


Bonus: Berikan contoh di mana makro benar-benar lebih baik daripada solusi tidak-makro.

Pertanyaan terkait: Kapan makro C ++ bermanfaat?

Trevor Boyd Smith
sumber
+1 untuk memberi perhatian pada penyalahgunaan yang merajalela yang telah saya derita di tangan makro.
i_am_jorf
37
#define true false // happy debugging :)
n0rd
Komunitas wiki berarti bahwa tidak ada yang akan mendapatkan (atau kehilangan) reputasi dari suara naik / turun pada pertanyaan ini atau jawabannya. Banyak orang melihat pertanyaan seperti ini sebagai cara yang murah dan mudah untuk mendapatkan reputasi, jadi jika Anda menandainya sebagai komunitas wiki, orang cenderung tidak akan merasa bengkok dan menutupnya.
Graeme Perrow
2
"orang cenderung menjadi bengkok dan menutupnya": Apakah Anda menyiratkan bahwa Anda tidak ingin ada konten lucu / lucu pada stack overflow?
Trevor Boyd Smith
2
Hanya titik cepat, pra-prosesor adalah bagian dari bahasa dan karenanya tidak jahat / salah untuk digunakan, sama seperti yang lain.
Tn. Boy

Jawaban:

410

Dari memori, itu terlihat seperti ini:

#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)

Ya itu benar, tidak ada kurung kurawal di salah satu fungsi. Penyorotan sintaksis berantakan, jadi dia menggunakan vi untuk mengedit (bukan vim, memiliki pewarnaan sintaks!)

Dia adalah seorang programmer Rusia yang sebagian besar bekerja dalam bahasa assembly. Dia fanatik tentang menyimpan byte sebanyak mungkin karena dia sebelumnya bekerja pada sistem dengan memori yang sangat terbatas. "Itu untuk satelit. Hanya sangat sedikit byte, jadi kami menggunakan setiap byte untuk banyak hal." (agak mengutak-atik, menggunakan kembali instruksi mesin byte untuk nilai numeriknya) Ketika saya mencoba mencari tahu jenis satelit apa, saya hanya bisa mendapatkan "satelit pengorbitan. Untuk membuat mengorbit."

Dia memiliki dua keanehan lain: Sebuah cermin cembung dipasang di atas monitornya "Untuk mengetahui siapa yang menonton", dan sesekali keluar tiba-tiba dari kursinya untuk melakukan sepuluh push up cepat. Dia menjelaskan yang terakhir ini sebagai "Kompiler menemukan kesalahan dalam kode. Ini adalah hukuman".

pengguna78859
sumber
87
"Kompilator menemukan kesalahan dalam kode. Ini adalah hukuman". !! Perusahaan menemukan Anda ... hukuman kepada sesama karyawan!
Belajar
227
Di Soviet Rusia, program mengkompilasi ANDA!
Crashworks
53
Ketika saya membaca tentang kesalahan penyusun "hukuman", hal pertama yang saya pikirkan adalah "Dobby harus menyeterika tangannya".
Graeme Perrow
124
Saya pikir programmer (termasuk saya sendiri) akan jauh lebih cocok jika kita semua melakukan 10 push up setiap kali kompiler menemukan kesalahan dalam kode kita. Ini juga dapat mengurangi terjadinya pengujian dengan kompilasi.
MikeyB
5
Pria itu terdengar luar biasa. Tapi ya, saya tidak melihat bagaimana ini seharusnya meningkatkan ukuran kode.
jalf
274

Terburuk saya:

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

Saya menghabiskan dua hari dalam hidup saya melacak beberapa masalah penghitungan ref COM multi-threaded karena beberapa orang idiot memasukkan ini ke dalam file header. Saya tidak akan menyebut perusahaan tempat saya bekerja saat itu.

Moral dari cerita ini? Jika Anda tidak mengerti sesuatu, baca dokumentasi dan pelajari tentangnya. Jangan membuatnya hilang begitu saja.

i_am_jorf
sumber
146
@ Yosua: Jika Anda menjalankan kode ini di lingkungan multithreaded, Anda mungkin tidak sengaja melakukannya
1800 INFORMASI
11
"Jika kamu tidak mengerti sesuatu, baca dokumentasi dan pelajari tentang hal itu. Jangan hanya membuatnya hilang." - AMIN!
Paul Alexander
2
@ 1800 Informasi: Saya pikir Anda hanya akan kehilangan suara, itulah sebabnya saya tidak dapat memberikan Anda satu; p
wkf
5
Maafkan saya sebagai programmer non-C ++: Apakah masalah utama di sini bahwa fungsi threadsafe diubah menjadi yang bukan-threadsafe? Atau bahwa InterlockedIncrement mengharapkan pointer, jadi sekarang Anda akan meningkatkan pointer daripada menunjuknya? Atau keduanya?
Tim Pietzcker
38
Masalahnya adalah bahwa InterlockedIncrement biasanya merupakan fungsi atom yang didefinisikan dalam Windows API. Jadi, ketika orang memanggil InterlockedIncrement, mereka berharap untuk memanggil fungsi yang dijamin akan dieksekusi secara atom. Sebagai gantinya, seseorang mendefinisikan makro dengan nama yang sama, yang dievaluasi menjadi peningkatan sederhana, non-atom
jalf
166
#define ever (;;)
for ever { 
   ...
}
Joel Spolsky
sumber
52
Saya lebih suka <#define selamanya untuk (;;)> sehingga Anda dapat menulis <forever {...}>
paxdiablo
seseorang yang saya pergi ke sekolah dengan tanda hilang untuk hal yang PERNAH ... dia tersedak seperti itu di buku teks :-)
TofuBeer
6
Bukankah saran Pax langsung dari K&R? Tetap saja, tidak sepadan dengan usaha, kataku.
Jon Ericson
Itu sebenarnya tidak buruk sama sekali. Saya tidak menggunakan for (;;)idiom, kalau tidak saya akan segera menambahkan makro ini ke kode saya.
AnT
1
@hayalci: Di ​​emacs lisp (dan beberapa implementasi umum lisp) Anda bisa melakukannya (defmacro ever ())dan kemudian(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!");
}

Tantangan: Adakah yang bisa melakukannya dengan sedikit definisi dan struct? ;-)

jujur
sumber
19
Anda baru saja menulis konverter java-to-c! mengerikan!
Andreas Petersson
25
Dilaporkan sebagai "ofensif." (I kid!)
Annika Backstrom
40
Itu bisa sangat indah atau sangat indah.
Chris Lutz
38
@ Mark - Ini menyatakan publicdan static as nothing, membatalkan` sebagai int, dan main(x)sebagai main(), jadi public static void main(String[] args)berubah menjadi int main(). Kemudian Systemberubah menjadi S s;s, jadi System.out.println("Hello World!");berubah menjadi S s; s.out.println("Hello World!");yang memanggil printlnfungsi dalam Fstruct di Sstruct.
Chris Lutz
2
Lihatlah ini: mailcom.com/ioccc/chia/chia.c (unduh dan kompilasi)
Roberto Bonvallet
130
#define private public
Andy White
sumber
Saya pernah melakukan itu sebelumnya. Kadang-kadang Anda hanya perlu memodifikasi variabel anggota atau mengganti fungsi dalam beberapa kode pihak ketiga yang tidak dapat Anda ubah - dan mereka tidak menyediakan accessor untuk Anda.
Michael Kristofik
30
wow untuk pengujian unit ini bahkan mungkin berguna, meskipun hantu desain objek akan menghantui Anda di malam hari.
Epaga
12
Hmmm, perilaku tidak terdefinisi, pelanggaran aturan satu definisi, mudah perbedaan tata letak. Yup, ini adalah pemenangnya.
David Thornley
10
Jadi dengan itu, saya dapat mengakses hal-hal pribadi dan publik, tetapi tidak hal-hal yang dilindungi, dan saya tidak dapat mengakses hal-hal antara classkata kunci dan pengubah akses pertama.
Ken Bloom
3
@ Ken:#define class struct #define protected public
Yakov Galka
107
#define if while

Itu adalah lelucon yang dimainkan pada seseorang, tidak ditemukan lucu oleh mereka yang terpengaruh

Michael McCarty
sumber
22
# tentukan sementara jika akan lebih berbahaya.
starblue
7
Kami harus mengklarifikasi pernyataan Anda. Tidak ditemukan lucu oleh orang-orang yang terkena dampak . :-)
Andrew Shepherd
6
Ketika saya mengerjakan tugas pekerjaan rumah, saya sering melakukan hal-hal semacam ini dengan sengaja, hanya untuk mengganggu guru saya.
pyon
15
Ini adalah lelucon yang bagus tetapi tidak dapat dikompilasi jika ada pernyataan "lain". Saya telah menemukan bahwa #define if (x) if (true) paling efektif.
Grafik Noob
32
Saya selalu lebih suka #define sizeof (x) rand ()
Jon
106

Yang mengerikan:

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

Serius, jika Anda ingin kode dalam Pascal, beli kompilator Pascal, jangan hancurkan bahasa C yang indah.

paxdiablo
sumber
45
Sekarang Anda membuat saya bertanya-tanya bahasa apa yang bisa saya simulasikan dengan file header yang cukup pintar.
Bill the Lizard
47
C tidak cantik. Agak jelek.
rlbond
27
Keindahannya terletak pada kesederhanaannya. Sudah dikatakan memiliki semua kecepatan bahasa assembly dikombinasikan dengan keterbacaan dari ... bahasa assembly :-) Saya lebih suka itu daripada C ++ kembung (meskipun saya lebih suka Jawa dalam pekerjaan saya hari karena perpustakaan yang sangat besar).
paxdiablo
9
Tidak benar-benar. Temukan sumber asli Bourne untuk shell bourne. Dia melakukan ini untuk mendapatkan kekacauan seperti ALGOL.
RBerteig
3
#define DO untuk (int _i = 0; _i <= 1; ++ _ i) {if (_i == 1) //// LINE BREAK //// #define IF (cond); if (! (cond)) break; } //// LINE BREAK //// DO printf ("a") IF (1 == 2);
Adrian Panasiuk
93

Seorang 'arsitek', pria yang sangat rendah hati, Anda tahu tipenya, memiliki yang berikut:

#define retrun return

karena dia suka mengetik cepat. Ahli bedah otak dulu suka meneriaki orang-orang yang lebih pintar darinya (yang hampir semuanya), dan mengancam akan menggunakan sabuk hitamnya pada mereka.

dcw
sumber
Saya membuat kesalahan ketik itu sehingga saya benar-benar mempertimbangkannya.
Joshua
4
alih-alih ajari editor Anda untuk mengembalikan secara otomatis kembali. Saya sudah melakukan peretasan seperti itu ke klien IRC saya, setidaknya
Tetha
1
Hei, saya pikir saya dulu bekerja dengan 'arsitek' itu juga. Dia akhirnya direklasifikasi sebagai arsitek senior ketika egonya perlu diredakan.
BIBD
1
Saya telah 'rn' didefinisikan ulang menjadi 'rm' di bash, karena saya tidak dapat mengetik dan pembaca berita 'rn' memerlukan waktu 5 menit untuk memulai dan terhubung ke server.
Martin Beckett
2
Anda tidak bisa hanya membuka terminal baru (atau beralih ke vt lain) dan lakukan killall rn?
Joe D
69

Dunia nyata? MSVC memiliki makro di minmax.h, dipanggil maxdan min, yang menyebabkan kesalahan kompilator setiap kali saya bermaksud menggunakan std::numeric_limits<T>::max()fungsi standar .

xtofl
sumber
2
Ah, ya, itu sebabnya saya memiliki tajuk khusus dengan # # undef kewarasan setelah MS-spesifik ...
Pontus Gagge
3
Diselesaikan dengan (std :: numeric_limits <T> :: max) () Tapi ya, cukup menyebalkan.
rlbond
36
Tambahkan NOMINMAX ke properti proyek Anda di bawah C / C ++ -> Preprocessor -> Definisi Preprocessor.
mattnewport
18
Makro ini telah ada di header MS lebih lama dari min dan maks telah berada di Perpustakaan Standar C ++.
Richard
4
Lebih buruk lagi ketika empat dari dependensi eksternal Anda yang lain juga menentukan min / max dari mereka sendiri, dari berbagai tingkat kesuksesannya, mulai dari makro dengan tanda kurung buruk hingga template yang ditulis dengan baik, dan salah satunya hanya perlu membuatnya tidak mungkin untuk tidak terdefinisi. atau lewati ini ... Dalam buku saya bahasa yang harus disalahkan adalah 50%.
Roman Starkov
58

Gabungan antara sintaks Pascal dan kata kunci Prancis:

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }
mouviciel
sumber
36
#define zut_alors exit (-1)
MikeyB
4
Itu luar biasa dan itu membuat saya tertawa terbahak-bahak. Jadi, ini pada dasarnya adalah versi bahasa Prancis dari Basic yang diimplementasikan dalam bahasa C?
Bobby
56

Raymond Chen memiliki kata-kata kasar yang sangat baik terhadap penggunaan macro kontrol aliran . Contoh terbaiknya adalah langsung dari kode sumber shell Bourne asli:

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
}
INFORMASI 1800
sumber
2
Dua poin: satu, tempel ini mengacaukan lekukan aslinya. Dan kedua, kodenya terlihat bagus: 1970-an Unix C oleh penggemar Algol-68. Jika _ mengapa orang yang beruntung bisa mengekspresikan dirinya dalam gaya yang unik, mengapa Steve Bourne tidak bisa? Tentu saja, seseorang yang dikutuk untuk mempertahankannya yang tidak tahu Algol 68 mungkin tidak menghargai kesempatan ini untuk memperluas selera mereka sendiri.
Darius Bacon
Saya pikir ini mungkin dimaksudkan sebagai lelucon oleh Steve Bourne daripada gaya pemrograman yang disarankan
Martin Beckett
2
Saya telah melihat if... else... elif... fidan case... esacsebelumnya (dalam bahasa yang diciptakan Bourne untuk sh), tapi loop... pooladalah permata yang nyata.
hobbs
54

Saya ingin mengirimkan permata yang disebut chaos-pp untuk kontes , yang mengimplementasikan bahasa fungsional melalui macro preprocessor.

Salah satu contohnya adalah menghitung angka fibonacci ke-500 seluruhnya oleh preprocessor:

Kode asli sebelum preprosesor terlihat seperti ini:

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

preprocessing file kita mendapatkan hasil berikut (setelah menunggu agak lama):

$ 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;
}
Andrew Y
sumber
1
Anda dapat mengambil kode dari CVS dan melihatnya. Saya telah memasukkan beberapa detail tentang hal ini ke dalam blogpost saya beberapa waktu yang lalu ketika saya menemukan itu: bnpcs.blogspot.com/2009/02/... Jika bukan karena masalah dengan debugging kode yang dihasilkan (masalah memiliki garis yang sangat panjang jika mereka dihasilkan oleh seperti "bahasa"), itu bisa saja bahkan dapat digunakan sebagai kode-generator praktis untuk C.
Andrew Y
Saya hanya bisa membayangkan butuh waktu lama untuk dikompilasi
Paul Fultz II
52

Langsung dari Qt:

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

Benar-benar baik untuk berinteraksi dengan lib lain sebagai penambah :: sinyal ... Hanya sebuah contoh, ada banyak lainnya di Qt yang membuat kode tampak lucu seperti:

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

Dan itu adalah C ++ ... tapi tiba-tiba:

boost::signals::trackable

Tidak berlaku lagi C ++.

David Rodríguez - dribeas
sumber
5
:) Jadi itu adalah makro yang merusak perpustakaan lain tanpa biaya. Itu bahkan lebih baik daripada yang saya harapkan :)
David Rodríguez - dribeas
38
Qt adalah sangat teritorial dan kejam akan menyerang perpustakaan lain yang mencoba untuk menempati namespace nya :)
Jeremy Friesner
21
Sayangnya Qt menyerang perpustakaan di luar ruang namanya dengan menggunakan makro
David Rodríguez - dribeas
7
Untungnya meningkatkan :: signals2 tetap memiliki masalah ini;)
bdonlan
9
Gunakan Q_SIGNALS dan Q_SLOTS jika Anda takut interaksi ini.
Tadeusz A. Kadłubowski
50

Windows.h memiliki banyak fungsi yang menyalahgunakan makro.


MrValdez terganggu oleh makro GetObject yang ditemukan di Windows.h

Makro GetObject mengubah fungsi GetObject () menjadi GetObjectA () atau GetObjectW () (tergantung apakah build dikompilasi dalam non-unicode dan unicode, masing-masing)

MrValdez benci harus melakukan sebelum jalur fungsi GetObject

#undef GetObject

Object *GetObject()

Alternatifnya adalah mengubah nama fungsi menjadi sesuatu yang lain seperti GetGameObject ()


jdkoftinoff di komentar telah berhasil: Masalahnya adalah semua fungsi windows API adalah makro.

Adam Rosenfield menyebutkan bahwa masalah tersebut dapat diperbaiki dengan mendefinisikan NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX, dll sebelum memasukkan windows.h untuk menghapus masalah tersebut.

MrValdez
sumber
3
Anda dapat menekan ini tetapi # mendefinisikan NOGDI sebelum memasukkan windows.h, asalkan tentu saja Anda tidak perlu menggunakan salah satu dari berbagai fungsi GDI. Ada banyak makro lain seperti WIN32_LEAN_AND_MEAN, NOMINMAX, dll. Yang menekan hal-hal lain agar tidak didefinisikan atau dimasukkan.
Adam Rosenfield
1
GetObject adalah nama fungsi yang cukup umum. Mungkin Anda bisa menggunakan nama yang lebih deskriptif dengan konteks untuk menghindari tabrakan. Namun, itu adalah kasus makro yang cukup jahat.
strager
1
Sangat menjengkelkan bahwa win32 memiliki semua makro untuk mengkonversi nama API ke FooA dan FooW. Kami memiliki masalah dengan SendMessage.
i_am_jorf
6
Masalahnya adalah bahwa semua fungsi Windows API adalah makro. Salah satu yang menggigit saya adalah GetTickCount (). Karena saya melakukan sebagian besar pemrograman saya di luar windows, saya menemukan semua definisi di header windows dan kemudian membuat file saya sendiri yang menentukan semuanya untuk memverifikasi kompatibilitas sebelumnya.
jdkoftinoff
12
Saya pikir kita punya pemenang. Ini adalah dunia nyata, itu ide yang sangat buruk, dan itu memengaruhi sejumlah besar programmer yang tidak bersalah. Siapa pun yang bertanggung jawab atas permata ini di Microsoft harus dianggap sebagai penjahat perang ... Bagian terbaiknya adalah Microsoft tidak berpikir dua kali untuk menggunakan nama yang luar biasa umum, seperti GetObject, SendMessage atau CreateWindow.
jalf
45
#define return if (std::random(1000) < 2) throw std::exception(); else return

ini sangat jahat. Ini acak, yang artinya menyala di tempat yang berbeda sepanjang waktu, itu mengubah pernyataan kembali, yang biasanya memiliki beberapa kode di atasnya yang bisa gagal dengan sendirinya, itu mengubah kata kunci tampak tidak bersalah yang Anda tidak akan pernah curiga dan ia menggunakan pengecualian dari ruang std sehingga Anda tidak akan mencoba mencari melalui sumber Anda untuk menemukan sumbernya. Sangat brilian.

vava
sumber
4
Baru saja menguji yang ini, setidaknya tidak dikompilasi secara default karena tidak ada yang termasuk untuk acak, dan itu merah berlekuk lalu. Namun, jika Anda memasukkannya secara tidak sengaja, segalanya menjadi lebih buruk - VC ++ 2010 menandainya masih sebagai kata kunci dan tidak menampilkan tooltip ekspansi makro, jadi tidak ada bantuan dari IDE untuk menemukan ini: - /
OregonGhost
Aku menyukainya! Jenius murni. Bayangkan seberapa baik Anda dapat melihat ketika Anda "Debug" Aplikasi ini ketika tidak ada orang lain yang berhasil.
brice
36

Seorang rekan kerja dan saya menemukan dua permata ini di beberapa kode kami untuk streaming objek. Makro ini dipakai di file kelas SETIAP TUNGGAL yang melakukan streaming. Tidak hanya kode mengerikan ini memuntahkan seluruh basis kode kami, ketika kami mendekati penulis asli tentang hal itu, ia menulis artikel 7 halaman di wiki internal kami membela ini sebagai satu-satunya cara yang mungkin untuk mencapai apa yang ia coba lakukan di sini.

Tidak perlu dikatakan lagi, sejak itu telah di-refactored dan tidak lagi digunakan di basis kode kita.

Jangan dibuang dengan kata kunci yang disorot. Ini SEMUA makro

#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> )

Pembaruan (17 Desember 2009):

Berita baik lainnya tentang penulis makro yang mengerikan ini. Pada Agustus, karyawan yang bertanggung jawab atas keburukan ini dipecat.

Grant Limberg
sumber
3
dia jelas belum pernah mendengar tentang: "Debugging dua kali lebih keras daripada menulis kode di tempat pertama. Karena itu, jika Anda menulis kode sepintar mungkin, Anda, menurut definisi, tidak cukup pintar untuk men-debug itu." -Brian W. Kernighan
Trevor Boyd Smith
33

Saya melakukan yang berikut sendiri, dan saya pikir saya belajar sesuatu darinya.

Pada tahun 1992, saya menulis interpreter Lisp kecil. Itu tidak diimplementasikan dalam C normal, tetapi dalam bahasa seperti C ditafsirkan. Bahasa C-like ini menggunakan pre-processor C standar.

Interpreter Lisp tentu saja berisi fungsi mobil , yang digunakan dalam Lisp untuk mengembalikan elemen pertama dalam daftar, dan cdr , yang mengembalikan sisa daftar. Mereka diimplementasikan seperti ini:

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 */

(Data disimpan dalam array, karena tidak ada struct. CONS_OFFSET adalah 1000 konstan.)

mobil dan cdr sering digunakan dalam Lisp, dan pendek, dan karena pemanggilan fungsi tidak terlalu cepat dalam bahasa implementasi, saya mengoptimalkan kode saya dengan mengimplementasikan kedua fungsi Lisp tersebut sebagai makro:

#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 memeriksa bahwa argumennya sebenarnya adalah sebuah daftar, dan karena argumen itu juga sering digunakan dalam penerjemah, dan pendek, saya menulis argumen itu juga sebagai makro:

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

IS_CONS dan LISP_ERROR juga sering digunakan, jadi saya membuatnya menjadi makro juga:

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

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

Tampaknya masuk akal?

Tapi kemudian, mengapa seluruh sistem crash pada baris ini:

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

Saya bekerja lama untuk menemukan masalah, sampai akhirnya saya memeriksa jalur pendek yang dikembangkan oleh pra-prosesor. Itu diperluas ke baris 31370 karakter, yang saya miliki di sini dibagi menjadi garis (502 dari mereka) untuk kejelasan:

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))
Thomas Padron-McCarthy
sumber
18
I optimized my code by implementing those [..] functions as macros- Kata-kata terakhir yang terkenal ...
BlueRaja - Danny Pflughoeft
3
Saya melakukan pelanggaran serupa di versi awal penerjemah Postscript saya. Push dan pop adalah fungsi yang sangat penting sehingga harus makro . Tetapi menyusun ekspresi yang melibatkan lebih dari satu di antaranya mengarah pada perilaku yang tidak terdefinisi. Perilaku tidak terdefinisi hanya ditangkap saat kompilasi di -O3. Dan pada -O3 versi fungsi akan diuraikan pula.
luser droog
29

Saya pernah harus mem-port aplikasi C dari unix ke windows, yang sifatnya spesifik yang tetap tidak disebutkan namanya untuk melindungi yang bersalah. Orang yang menulisnya adalah seorang profesor yang tidak terbiasa menulis kode produksi, dan jelas datang ke C dari bahasa lain. Itu juga terjadi bahwa bahasa Inggris bukan bahasa pertamanya, meskipun negara tempat dia berasal dari mayoritas orang berbicara dengan cukup baik.

Aplikasinya banyak menggunakan preprocessor untuk memutar bahasa C ke dalam format yang lebih baik dimengerti. Tetapi macro yang paling banyak digunakannya didefinisikan dalam file header bernama 'Thing.h' (serius), yang termasuk yang berikut:

#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 ->

... yang kemudian dia gunakan untuk menulis monstrositas seperti berikut:

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);
}

Seluruh proyek (~ 60.000 LOC) ditulis dengan gaya yang sama - marco hell, nama-nama aneh, jargon Inggris Kuno, dll. Untungnya kami dapat membuang kode tersebut karena saya menemukan perpustakaan OSS yang melakukan lusinan algoritma yang sama. kali lebih cepat.

(Saya sudah menyalin dan mengedit jawaban ini yang semula saya buat untuk pertanyaan ini ).

Nik Reiman
sumber
3
Saya agak terpesona oleh posesif dan bahasa Inggris kuno, karena semua itu tentu saja saya setuju kode terlihat mengerikan.
Darius Bacon
27

Yang terburuk yang pernah saya temui adalah dalam sebuah produk yang berisi serangkaian executable di mana pemimpin teknis yang ditunjuk belum menemukan perpustakaan.

Sebagai gantinya, ia memiliki set file yang dibagikan di beberapa folder Visual Source Safe. Dia kemudian menyadari bahwa mereka perlu berperilaku sedikit berbeda untuk setiap aplikasi.

Ada sejumlah langkah refactoring yang bisa Anda terapkan di sini.

Sebaliknya, ia menggunakan #ifdefs

   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
   }
Andrew Shepherd
sumber
17

Penggunaan preprosesor LINE untuk menghasilkan ID unik untuk pesan yang melewati jaringan:

NetworkMessages.h

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

Ini adalah contoh di mana makro benar-benar lebih baik daripada solusi non-makro:

Dalam kelas solusi non-makro, fungsi dan variabel harus dibangun untuk melacak ID apa pesan itu. Pengembang mungkin atau mungkin tidak mempersulit pelacakan ID pesan sedangkan ini lebih mudah dibaca dan di-debug.

Selain itu, lebih mudah untuk menambahkan pesan baru hanya dengan menambahkan pesan ke sumbernya.

Kerugian dari situasi ini adalah bahwa file harus dimasukkan dalam semua kode yang menggunakan pesan. Waktu kompilasi akan meningkat setiap kali sebuah pesan diedit.

MrValdez
sumber
8
Dan versi mungkin tidak kompatibel satu sama lain (tidak baik!). Kenapa enum tidak cukup?
strager
Baik ini dan Enum memiliki masalah ketidakcocokan yang sama persis.
MrValdez
17
Sekarang saya datang dan mengurutkan #define ... dan protokol berubah. Atau saya mendapatkan agama Doxygen dan mendokumentasikan semua kode pesan, dan protokolnya berubah. Setidaknya enum stabil di bawah perubahan yang terakhir.
RBerteig
3
@MrValdez, itu kurang ketat untuk menjaga blok enum dalam urutan, daripada tetap mendefinisikan pada baris yang sama relatif terhadap file mulai.
peterchen
Saya tahu bahwa ini adalah pos lama, tetapi apakah ini berfungsi? Maksud saya #define hanya akan mengganti konstanta pesan ke LINE dan hanya kemudian LINE akan diperluas ke nomor baris, jadi setiap kali kita menggunakan konstanta yang sama pada baris yang berbeda - itu akan berubah (ke nomor baris saat ini)?
XzKto
16

Satu contoh yang cukup buruk:

#ifdef __cplusplus
#define class _vclass
#endif

Ini memungkinkan struktur C yang berisi variabel anggota dipanggil classuntuk ditangani oleh kompilator C ++. Ada dua header dengan konstruk ini di dalamnya; salah satunya juga berisi 'kelas undef' di akhir dan yang lainnya tidak.

Jonathan Leffler
sumber
1
Inilah sebabnya mengapa Objective-C menggunakan @classbukan class.
14

Dalam satu tahun Kontes Coding Canggu Internasional, ada entri di mana seluruh program adalah:

P

Dengan syarat yang bisa Anda definisikan Pdi makefile menjadi program apa pun yang Anda inginkan.

Seingat saya, itu menang di salah satu kategori, dan tahun berikutnya muncul peraturan yang melarang gaya masuk itu.

(Sunting: enam bulan kemudian atau sesuatu ... Saya yakin hal "No IOCCC" tidak ada dalam pertanyaan utama ketika saya menulis ini ...)

Kaz Dragon
sumber
12

Saya bosan suatu hari dan bermain-main dengan balok di 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)

memungkinkan hal-hal "menarik" seperti:

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)))));

(beberapa definisi fungsi dan kelas tidak ditampilkan untuk singkatnya)

cobbal
sumber
"Aku bosan suatu hari" kata-kata terakhir pengembang terkenal :)
Richard J. Ross III
11

Yang terburuk yang saya lihat adalah yang tidak digunakan :-)

Seseorang menulis strcpy (saya pikir itu saja ... lebih dari 10 tahun yang lalu sekarang) berfungsi di dalam metode (karena mereka tidak ingin overhead memanggil strcpy ... huh).

Mereka memberi petunjuk bahwa itu tidak akan berfungsi untuk karakter Jepang sehingga mereka menambahkan "jika" di awal untuk melakukan ASCII atau Unicode. Pada saat itu, kodenya panjangnya sekitar satu layar ... kemungkinan membunuh koherensi cache dan menghapus simpanan yang seharusnya untuk inlining kode.

Kode identik simpan untuk jenis (jadi harus menggunakan makro).

Tentu saja strcpy yang mereka tulis jauh lebih lambat daripada assembler yang disetel di perpustakaan standar ...

Tentu saja jika mereka baru saja melakukan semuanya sebagai makro bisa diganti dengan panggilan ke strcpy ...

Tentu saja saya keluar dari perusahaan (tidak langsung karena itu ...)

TofuBeer
sumber
The code was identical save for the types (so should have used a macro).Tidak, dia seharusnya menggunakan templat.
BlueRaja - Danny Pflughoeft
1
Dia seharusnya menggunakan strcpy bawaan! (dan itu kode C bukan C ++ jadi tidak ada templat) :-P
TofuBeer
Optimalisasi prematur adalah akar dari semua kejahatan.
Hubert Kario
11

Wajib

#define FOR  for

dan

#define ONE  1
#define TWO  2
...

Siapa yang tahu?

Sial
sumber
5
Tapi-tapi-tapi TIDAK ADA SASTRA DALAM KODE! ;)
Bernard
mereka masih literal mon, harus nama mereka dengan tujuan / maksud bukan simbol alternatif. Kode COBOL Saya mendengar tentang mereka membuat variabel 5 = 5 kemudian kemudian kode mengatakan set 5 = 10 ... orang-orang di mana benar-benar terkejut ketika mereka melakukan var + 5 dan mendapat var + 10.
Greg Domjan
1
Belum pernah mendengarnya dengan COBOL, hanya dengan FORTRAN. COBOL, tentu saja, memiliki NOL, ZEROS, dan NOL sebagai kata-kata yang dilindungi undang-undang, semuanya berarti hal yang sama persis dengan 0.
David Thornley
Jauh lebih baik daripada "#define ONE 0". Jika Anda ingin terkikik-kikik, cari di web untuk itu dan kaget dengan jumlah hit yang tidak nol.
Reuben
11
#define TRUE 0 // dumbass

Orang yang melakukan ini menjelaskan dirinya sendiri beberapa tahun kemudian - sebagian besar (jika tidak semua) fungsi C library mengembalikan 0 sebagai indikasi bahwa semuanya berjalan dengan baik. Jadi, dia ingin dapat menulis kode seperti:

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

Tak perlu dikatakan, tidak ada seorang pun di tim kami (penguji atau pengembang) yang pernah berani melirik kode-nya lagi.

Michael Foukarakis
sumber
1
saya menyalahkan fungsi pustaka C untuk membuat 0 "semuanya baik-baik saja": P
RCIX
6
Mengapa tidak mendeklarasikan sesuatu seperti #define FLAG_SUCCESS 0?
pyon
11

Saya memelihara kode yang memiliki gotos di makro. Jadi suatu fungsi akan memiliki label di bagian akhir tetapi tidak ada goto yang terlihat dalam kode fungsi. Yang memperburuk makro adalah di akhir pernyataan lain biasanya dari layar kecuali Anda gulir secara horizontal.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}
batal
sumber
Yang lebih buruk adalah ketika makro menyembunyikan kedua gotopernyataan serta definisi label target. Benar-benar ajaib.
Reuben
Saya sudah menderita itu - tetapi makro tampak seperti pemanggilan fungsi.
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!");
}
jujur
sumber
3
Dan ANDA ingin menulis runtime. Lihatlah berapa banyak waktu yang saya hemat!
Bernard
4
@ Trevor: Ya ... yang pintar masih melakukan Java sebagai gantinya. mencalonkan diri
Michael Myers
Jika Anda meletakkan [] setelah args sebagai ganti sebelumnya, dan "#define String int argc, char *", itu akan dikompilasi (dengan sedih).
Adam Rosenfield
16
Saya suka yang lain lebih baik. Yang ini menunjukkan sesuatu yang dekat dengan Jawa sedang ditulis dengan beberapa makro. Yang lain menunjukkan Jawa persis yang ditulis dengan sejumlah makro licik dan struct dengan anggota fungsi. Yang pertama adalah lelucon murah, sedangkan yang kedua adalah lelucon yang rumit dan baik.
Chris Lutz
10

Oleh teman sekelas yang gagal memahami aturan tentang angka ajaib:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1

Rubi
sumber
9

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

Anda benar-benar harus mengunduhnya untuk menghargainya. Seluruh alur kerja ditentukan oleh makro. Ini benar-benar tidak dapat dibaca. Sebagai contoh -

 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 {

dll, dll.

Dan itu hanya mengatur opsi. seluruh program seperti itu.

Steve
sumber
2
Ya Tuhan ... kurasa aku pusing.
Michael Foukarakis