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?
c++
c
macros
preprocessor
Trevor Boyd Smith
sumber
sumber
Jawaban:
Dari memori, itu terlihat seperti ini:
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".
sumber
Terburuk saya:
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.
sumber
sumber
for (;;)
idiom, kalau tidak saya akan segera menambahkan makro ini ke kode saya.(defmacro ever ())
dan kemudian(require 'cl (ever))
Tantangan: Adakah yang bisa melakukannya dengan sedikit definisi dan struct? ;-)
sumber
public
danstatic as nothing,
membatalkan` sebagaiint
, danmain(x)
sebagaimain()
, jadipublic static void main(String[] args)
berubah menjadiint main()
. KemudianSystem
berubah menjadiS s;s
, jadiSystem.out.println("Hello World!");
berubah menjadiS s; s.out.println("Hello World!");
yang memanggilprintln
fungsi dalamF
struct diS
struct.sumber
class
kata kunci dan pengubah akses pertama.#define class struct #define protected public
Itu adalah lelucon yang dimainkan pada seseorang, tidak ditemukan lucu oleh mereka yang terpengaruh
sumber
Yang mengerikan:
Serius, jika Anda ingin kode dalam Pascal, beli kompilator Pascal, jangan hancurkan bahasa C yang indah.
sumber
Seorang 'arsitek', pria yang sangat rendah hati, Anda tahu tipenya, memiliki yang berikut:
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.
sumber
killall rn
?Dunia nyata? MSVC memiliki makro di minmax.h, dipanggil
max
danmin
, yang menyebabkan kesalahan kompilator setiap kali saya bermaksud menggunakanstd::numeric_limits<T>::max()
fungsi standar .sumber
Gabungan antara sintaks Pascal dan kata kunci Prancis:
sumber
Raymond Chen memiliki kata-kata kasar yang sangat baik terhadap penggunaan macro kontrol aliran . Contoh terbaiknya adalah langsung dari kode sumber shell Bourne asli:
sumber
if
...else
...elif
...fi
dancase
...esac
sebelumnya (dalam bahasa yang diciptakan Bourne untuk sh), tapiloop
...pool
adalah permata yang nyata.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:
preprocessing file kita mendapatkan hasil berikut (setelah menunggu agak lama):
sumber
Langsung dari Qt:
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:
Dan itu adalah C ++ ... tapi tiba-tiba:
Tidak berlaku lagi C ++.
sumber
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
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.
sumber
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.
sumber
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
Pembaruan (17 Desember 2009):
Berita baik lainnya tentang penulis makro yang mengerikan ini. Pada Agustus, karyawan yang bertanggung jawab atas keburukan ini dipecat.
sumber
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:
(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:
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:
IS_CONS dan LISP_ERROR juga sering digunakan, jadi saya membuatnya menjadi makro juga:
Tampaknya masuk akal?
Tapi kemudian, mengapa seluruh sistem crash pada baris ini:
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:
sumber
I optimized my code by implementing those [..] functions as macros
- Kata-kata terakhir yang terkenal ...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:
... yang kemudian dia gunakan untuk menulis monstrositas seperti berikut:
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 ).
sumber
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
sumber
Penggunaan preprosesor LINE untuk menghasilkan ID unik untuk pesan yang melewati jaringan:
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.
sumber
Satu contoh yang cukup buruk:
Ini memungkinkan struktur C yang berisi variabel anggota dipanggil
class
untuk ditangani oleh kompilator C ++. Ada dua header dengan konstruk ini di dalamnya; salah satunya juga berisi 'kelas undef' di akhir dan yang lainnya tidak.sumber
@class
bukanclass
.Dalam satu tahun Kontes Coding Canggu Internasional, ada entri di mana seluruh program adalah:
P
Dengan syarat yang bisa Anda definisikan
P
di 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 ...)
sumber
Saya bosan suatu hari dan bermain-main dengan balok di Objective-C ...
memungkinkan hal-hal "menarik" seperti:
(beberapa definisi fungsi dan kelas tidak ditampilkan untuk singkatnya)
sumber
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 ...)
sumber
The code was identical save for the types (so should have used a macro).
Tidak, dia seharusnya menggunakan templat.Wajib
dan
Siapa yang tahu?
sumber
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:
Tak perlu dikatakan, tidak ada seorang pun di tim kami (penguji atau pengembang) yang pernah berani melirik kode-nya lagi.
sumber
#define FLAG_SUCCESS 0
?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.
sumber
goto
pernyataan serta definisi label target. Benar-benar ajaib.sumber
Oleh teman sekelas yang gagal memahami aturan tentang angka ajaib:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1
sumber
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 -
dll, dll.
Dan itu hanya mengatur opsi. seluruh program seperti itu.
sumber