Saya tidak mengerti konsep makro dengan baik. Apa itu makro? Saya tidak mengerti apa bedanya dengan fungsi? Baik fungsi dan makro berisi blok kode. Jadi bagaimana perbedaan makro dan fungsi?
programming-practices
Edoardo Sorgentone
sumber
sumber
Jawaban:
Catatan
Saya ingin menambahkan klarifikasi berikut setelah mengamati polarisasi pola pemungutan suara pada jawaban ini.
Jawabannya tidak ditulis dengan tetap mempertimbangkan akurasi teknis dan generalisasi luas. Itu adalah upaya sederhana untuk menjelaskan dalam bahasa yang sederhana, perbedaan antara makro dan fungsi untuk pemula pemrograman, tanpa mencoba untuk menjadi lengkap atau akurat (sebenarnya jauh dari akurat). Bahasa pemrograman C ada dalam pikiran saya ketika menyusun jawaban, tetapi permintaan maaf saya karena tidak menyebutkannya dengan jelas dan menyebabkan (potensi) kebingungan.
Saya sangat menghargai jawaban yang dibagikan oleh Jörg W Mittag . Itu adalah wawasan membaca itu (betapa saya tahu) dan saya memutakhirkannya segera setelah diposting. Saya baru saja memulai tentang Rekayasa Perangkat Lunak Stack Exchange, dan pengalaman serta diskusi sejauh ini sangat mendalam.
Saya akan meninggalkan jawaban ini di sini karena mungkin berguna untuk pemula pengembangan perangkat lunak lain, mencoba memahami konsep tanpa terjebak ke dalam akurasi teknis.
Baik makro dan fungsi merupakan unit kode mandiri. Keduanya adalah alat yang membantu dalam desain modular suatu program. Dari sudut pandang programmer yang menulis kode sumber, mereka tampak sangat mirip. Namun, mereka berbeda dalam cara mereka ditangani selama siklus pelaksanaan program.
Makro didefinisikan sekali dan digunakan di banyak tempat dalam suatu program. Makro akan diperluas inline selama tahap pra-pemrosesan. Dengan demikian, secara teknis tidak tetap menjadi entitas yang terpisah setelah kode sumber dikompilasi. Pernyataan dalam definisi makro menjadi bagian dari instruksi program, sama seperti pernyataan lainnya.
Motif di balik penulisan makro adalah untuk membuat penulisan dan pengelolaan kode sumber lebih mudah bagi programmer. Makro umumnya diinginkan untuk tugas-tugas sederhana di mana menulis fungsi penuh akan menjadi penalti overhead / runtime kinerja. Contoh situasi di mana makro lebih disukai daripada fungsi adalah:
Menggunakan nilai konstan (seperti nilai matematika atau ilmiah), atau beberapa parameter khusus program.
Mencetak pesan log atau menangani pernyataan.
Melakukan perhitungan sederhana atau memeriksa kondisi.
Saat menggunakan makro, mudah untuk membuat perubahan / koreksi di satu tempat yang tersedia secara instan di mana pun makro digunakan dalam program. Rekompilasi sederhana program diperlukan agar perubahan diterapkan.
Kode fungsi di sisi lain dikompilasi sebagai unit terpisah dalam program dan akan dimuat dalam memori selama eksekusi program hanya jika diperlukan. Kode fungsi mempertahankan identitas independennya dari sisa program. Kode yang dimuat akan digunakan kembali jika fungsinya dipanggil lebih dari satu kali. Ketika panggilan fungsi ditemui dalam program yang sedang berjalan, kontrol dilewatkan ke sana oleh subsistem runtime dan konteks program yang sedang berjalan (alamat instruksi pengembalian) dipertahankan.
Namun, ada sedikit penalti kinerja yang perlu dijumpai saat memanggil fungsi (pengalihan konteks, mempertahankan alamat pengirim dari instruksi program utama, meneruskan parameter dan menangani nilai pengembalian dll.). Oleh karena itu, penggunaan fungsi hanya diinginkan untuk blok kode yang kompleks (terhadap makro yang menangani kasus yang lebih sederhana).
Dengan pengalaman, seorang programmer membuat keputusan yang bijaksana apakah sepotong kode akan cocok sebagai makro atau fungsi dalam arsitektur program secara keseluruhan.
sumber
Sayangnya, ada beberapa penggunaan berbeda dari istilah "makro" dalam pemrograman.
Dalam rumpun bahasa Lisp, dan bahasa yang diilhami oleh mereka, serta banyak bahasa modern fungsional atau yang diilhami fungsional seperti Scala dan Haskell, serta beberapa bahasa imperatif seperti Boo, makro adalah sepotong kode yang berjalan pada waktu kompilasi (atau setidaknya sebelum runtime untuk implementasi tanpa kompiler) dan dapat mengubah Pohon Sintaksis Abstrak (atau apa pun yang setara dalam bahasa tertentu, misalnya dalam Lisp, itu akan menjadi S-Ekspresi) menjadi sesuatu yang lain selama kompilasi. Sebagai contoh, dalam banyak implementasi Skema,
for
adalah makro yang berkembang menjadi beberapa panggilan ke tubuh. Dalam bahasa yang diketik secara statis, makro sering mengetik aman, artinya mereka tidak dapat menghasilkan kode yang tidak diketik dengan baik.Dalam kelompok bahasa C, makro lebih seperti substitusi teks. Yang juga berarti mereka dapat menghasilkan kode yang tidak diketik dengan baik, atau bahkan tidak secara hukum sintaksis.
Dalam makro-assembler, "makro" merujuk ke "instruksi virtual", yaitu instruksi yang tidak didukung CPU secara asli tetapi bermanfaat, dan assembler memungkinkan Anda untuk menggunakan instruksi tersebut dan akan memperluasnya menjadi beberapa instruksi yang dimengerti oleh CPU. .
Dalam skrip aplikasi, "makro" mengacu pada serangkaian tindakan yang dapat "direkam" oleh pengguna dan "diputar ulang".
Semua itu dalam beberapa jenis kode dieksekusi, yang berarti mereka dalam beberapa hal dapat dilihat sebagai fungsi. Namun, dalam kasus macro Lisp, misalnya, input dan output mereka adalah fragmen program. Dalam kasus C, input dan output mereka token. Tiga yang pertama juga memiliki perbedaan yang sangat penting bahwa mereka dieksekusi pada waktu kompilasi . Faktanya, macro preprocessor C, seperti namanya, sebenarnya dieksekusi sebelum kode bahkan mencapai kompiler .
sumber
Dalam keluarga bahasa C definisi makro , perintah preprocessor, menentukan templat kode parametrized yang diganti pada panggilan makro tanpa dikompilasi pada definisi. Ini berarti bahwa semua variabel bebas harus terikat dalam konteks panggilan makro. Argumen parameter dengan efek samping seperti
i++
dapat diulangi, dengan penggunaan parameter yang jamak. Substitusi teks argumen1 + 2
beberapa parameterx
terjadi sebelum kompilasi, dan dapat menyebabkan perilaku yang tak terdugax * 3
(7
io9
). Kesalahan dalam tubuh makro definisi makro hanya akan ditampilkan pada saat kompilasi pada panggilan makro.The definisi fungsi kode menspesifikasikan dengan variabel bebas terikat pada konteks fungsi tubuh; bukan panggilan fungsi .
Makro namun tampaknya negatif menyediakan akses ke panggilan, nomor baris dan file sumber, argumen sebagai string .
sumber
Dalam istilah yang sedikit lebih abstrak, makro adalah untuk sintaks karena fungsinya adalah untuk data. Suatu fungsi (secara abstrak) merangkum beberapa transformasi pada data. Dibutuhkan argumennya sebagai data yang dievaluasi, melakukan beberapa operasi padanya, dan mengembalikan hasil yang juga hanya data.
Makro dalam kontras mengambil beberapa sintaks yang tidak dievaluasi dan beroperasi pada itu. Untuk bahasa mirip C, sintaksnya masuk pada level token. Untuk bahasa dengan makro seperti LISP, mereka mendapatkan sintaks direpresentasikan sebagai AST. Makro harus mengembalikan sepotong sintaks baru.
sumber
Sebuah makro umumnya mengacu pada sesuatu yang diperluas di tempat , menggantikan makro "panggilan" selama kompilasi atau pra-pengolahan dengan instruksi individual dalam bahasa target. Saat runtime, umumnya tidak akan ada indikasi di mana makro dimulai dan berakhir.
Ini berbeda dari subrutin , yang merupakan bagian dari kode yang dapat digunakan kembali yang terletak secara terpisah di memori, di mana kontrol dilewatkan saat runtime . "Fungsi", "prosedur", dan "metode" di sebagian besar bahasa pemrograman termasuk dalam kategori ini.
Sebagaimana dibahas oleh Jörg W Mittag , detail pastinya bervariasi di antara beberapa bahasa: di beberapa, seperti C, makro melakukan subtitusi teks dalam kode sumber; dalam beberapa, seperti Lisp, ia melakukan manipulasi bentuk perantara seperti Pohon Sintaks Abstrak. Ada juga beberapa area abu-abu: beberapa bahasa memiliki notasi untuk "fungsi sebaris", yang didefinisikan seperti fungsi, tetapi diperluas ke program yang dikompilasi seperti makro.
Sebagian besar bahasa mendorong pemrogram untuk beralasan tentang masing-masing subrutin secara terpisah, mendefinisikan kontrak jenis untuk input dan output, dan menyembunyikan informasi lain tentang kode panggilan. Seringkali ada dampak kinerja untuk memanggil subrutin yang tidak dikenakan makro, dan makro mungkin dapat memanipulasi program dengan cara yang tidak bisa dilakukan subrutin. Makro karenanya dapat dianggap "tingkat lebih rendah" daripada subrutin, karena mereka beroperasi pada basis yang kurang abstrak.
sumber
Makro dieksekusi saat kompilasi, dan fungsinya dijalankan saat run time.
Contoh:
Jadi selama kompilasi kode sebenarnya diubah menjadi:
sumber