Apa itu makro? Perbedaan antara makro dan fungsi?

16

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?

Edoardo Sorgentone
sumber
15
Apakah Anda mengacu pada bahasa pemrograman tertentu?
mkrieger1
15
Kamu perlu lebih spesifik; makro merujuk pada tiga konsep yang sangat berbeda, kira-kira makro gaya teks / preprosesor, makro Lisp, dan makro aplikasi.
chrylis -on strike-

Jawaban:

7

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.

Nimesh Neema
sumber
9
Bagaimana dengan fungsi inlining?
Nathan Cooper
1
Dalam bahasa C & makro makro bisa menjadi panggilan fungsi juga. Jadi membuat perbedaan antara keduanya tidak masuk akal.
Sombrero Chicken
5
Dan makro gaya-C sama sekali tidak mandiri - mereka tidak memperkenalkan ruang lingkup leksikal, dan memiliki akses tak terbatas ke nama lokal dalam ruang lingkup pada titik penggantian.
berguna
@Sombrero Chicken: Mungkin Anda bisa menunjukkan contohnya? Anda dapat memiliki makro yang MENGANDUNG panggilan fungsi, tetapi (AFAIK) makro bukan panggilan fungsi.
jamesqf
3
Ada banyak hal tentang jawaban ini yang menyesatkan. Contoh yang Anda sebutkan sama sekali tidak dengan cara apa pun situasi di mana makro 'lebih disukai' - justru sebaliknya. Makro tidak boleh digunakan untuk hal-hal itu kecuali ada alasan yang sangat bagus untuk itu. Kinerja umumnya bukan alasan yang baik untuk menggunakan makro sama sekali. Untuk alasan yang disebutkan dalam komentar lain, membenarkan penggunaan makro dengan cara ini cenderung menghasilkan kode rawan kesalahan dengan segala macam konsekuensi yang tidak disengaja, terutama dalam basis kode yang lebih besar.
Ben Cottrell
65

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, foradalah 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 .

Jörg W Mittag
sumber
1
“Dalam bahasa yang diketik secara statis, makro sering kali mengetik dengan aman, artinya mereka tidak dapat menghasilkan kode yang tidak diketik dengan baik” - benarkah? Bahasa apa yang Anda maksud? AFAICS, ini secara umum hanya mungkin untuk menjamin dalam bahasa yang diketik dependen. Di Haskell, makro TH hanya aman secara sintaksis, tetapi pemeriksa tipe berjalan sesudahnya. (Jadi tipe-bijaksana, mereka memberikan jaminan lebih sedikit daripada template C ++ lakukan).
leftaroundabout
1
Selain scripting aplikasi, saya rasa ketiga contoh yang Anda berikan tidak terlalu berbeda. Semua melakukan substitusi semacam ke dalam program, sebagai lawan melompat ke bagian kode bersama ketika dieksekusi.
IMSoP
Mungkin Anda dapat memperluas penyebutan makro C dengan konsep umum bahasa makro seperti M4, karena untuk C pada dasarnya spesifikasi menentukan bahasa makro bantu CPP dan menstandarisasikan penggunaannya dengan C.
JoL
1
Tema umum tampaknya bahwa makro menghasilkan kode untuk ditafsirkan sebagai bagian dari kode sumber program yang lebih besar, daripada dieksekusi ketika program dijalankan.
jpmc26
1
@ jpmc26 Saya akan mengatakan tema umum adalah substitusi di mana Anda melakukan hal kecil dan itu berkembang menjadi hal besar. Bahasa makro M4 tidak secara khusus dimaksudkan untuk kode. Anda dapat menggunakannya untuk menghasilkan teks apa pun. Ada juga makro keyboard, seperti jawaban yang disebutkan ini. Anda menekan 1 atau 2 kunci dan mereka memperluas ke jumlah penekanan tombol yang lebih besar. makro vim juga seperti itu. Simpan urutan besar perintah mode normal di bawah satu tombol, dan Anda memanggil urutan itu dengan menjalankan perintah mode normal yang menjalankannya.
JoL
2

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 argumen 1 + 2beberapa parameter xterjadi sebelum kompilasi, dan dapat menyebabkan perilaku yang tak terduga x * 3( 7io 9). 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 .

Joop Eggen
sumber
2

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.

Ashton Wiersdorf
sumber
0

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.

IMSoP
sumber
0

Makro dieksekusi saat kompilasi, dan fungsinya dijalankan saat run time.

Contoh:

#include <stdio.h>

#define macro_sum(x,y) (x+y)

int func_sum(x,y) {
    return x+y;
}

int main(void) {
    printf("%d\n", macro_sum(2,3));
    printf("%d\n", func_sum(2,3));
    return 0;
}

Jadi selama kompilasi kode sebenarnya diubah menjadi:

#include <stdio.h>

int func_sum(x,y) {
    return x+y;
}

int main(void) {
    printf("%d\n", (2+3));
    printf("%d\n", func_sum(2,3));
    return 0;
}
david72
sumber