Makro nedir? Makro ve fonksiyon arasındaki fark nedir?


16

Makro kavramını iyi anlamıyorum. Makro nedir? İşlevden nasıl farklı olduğunu anlamıyorum? Hem işlev hem de makro bir kod bloğu içerir. Peki makro ve fonksiyon arasındaki fark nedir?


15
Belirli bir programlama dilinden bahsediyor musunuz?
1919

15
Daha spesifik olmalısınız; makrosu kabaca C stili metin / önişlemci makroları, Lisp makroları ve uygulama makroları olmak üzere çok farklı üç kavramı ifade eder.
chrylis -on grev-

Yanıtlar:


7

Not

Bu cevabın polarize edici oylama şeklini gözlemledikten sonra aşağıdaki açıklamayı eklemek istiyorum.

Cevap teknik doğruluk ve geniş genelleme göz önünde bulundurularak yazılmadı. Tam veya doğru olmaya çalışmadan basit bir dilde, makrolar ve fonksiyonlar arasındaki farkı bir programlama acemi için açıklamak alçakgönüllü bir girişimdi (aslında doğru olmaktan çok uzaktır). Cevabı hazırlarken C programlama dili aklımdaydı, ama açık bir şekilde bahsetmediğim ve herhangi bir (potansiyel) karışıklığa neden olduğum için özür dilerim.

Jörg W Mittag'in paylaştığı yanıtı gerçekten dikkate alıyorum . Okumak için kavrayıcıydı (daha az biliyorum) ve gönderildikten kısa bir süre sonra iptal ettim. Yazılım Mühendisliği Yığın Değişimi'ne yeni başladım ve şu ana kadarki deneyim ve tartışmalar gerçekten içgörü kazandı.

Bu yanıtı burada bırakacağım, çünkü diğer yazılım geliştirme yeni başlayanlar için yararlı olabilir, teknik doğruluklara girmeden bir kavramı anlamaya çalışıyorum.


Hem makro hem de işlev bağımsız kod birimini temsil eder. Her ikisi de bir programın modüler tasarımına yardımcı olan bir araçtır. Kaynak kodunu yazan programcı açısından oldukça benzer görünüyorlar. Ancak, program yürütme yaşam döngüsü boyunca nasıl ele alındıklarında farklılık gösterirler.

Makro bir kez tanımlanır ve bir programdaki birçok yerde kullanılır. Makro, ön işleme aşamasında satır içi olarak genişletilir. Böylece, kaynak kodu derlendikten sonra teknik olarak ayrı bir varlık olarak kalmaz. Makro tanımındaki ifadeler, tıpkı diğer ifadeler gibi program talimatlarının bir parçası haline gelir.

Makro yazmanın arkasındaki sebep, kaynak kodun yazılmasını ve yönetilmesini programcı için kolaylaştırmaktır. Makrolar genellikle tam teşekküllü bir işlev yazmanın performans ek yükü / çalışma zamanı cezası olacağı daha basit görevler için istenir. Bir makronun işlev yerine tercih edilebilir olduğu durumlara örnekler:

  • Sabit değerleri (matematiksel veya bilimsel değerler gibi) veya programa özgü bazı parametreleri kullanma.

  • Günlük mesajlarını yazdırma veya iddiaları işleme.

  • Basit hesaplamalar veya durum kontrolleri yapmak.

Makro kullanırken, makroda programın kullanıldığı her yerde anında kullanılabilen tek bir yerde değişiklik / düzeltme yapmak kolaydır. Değişikliklerin etkili olması için programın basit bir şekilde yeniden derlenmesi gerekir.

Diğer yandan fonksiyon kodu, program içinde ayrı bir birim olarak derlenir ve programın yürütülmesi sırasında sadece gerektiğinde belleğe yüklenir. İşlev kodu programın geri kalanından bağımsız kimliğini korur. İşlev birden çok kez çağrılırsa yüklenen kod yeniden kullanılır. Çalışan programda işlev çağrısı ile karşılaşıldığında, kontrol çalışma zamanı alt sistemi tarafından ona aktarılır ve çalışan programın içeriği (iade talimatı adresi) korunur.

Bununla birlikte, bir işlevi çağırırken karşılaşılması gereken hafif bir performans cezası vardır (bağlam değiştirme, ana program talimatlarının dönüş adresini koruma, parametreleri geçirme ve dönüş değerlerini işleme vb.). Bu nedenle, fonksiyonun kullanımı sadece karmaşık kod blokları için (daha basit durumları işleyen makrolara karşı) istenir.

Tecrübe ile, bir programcı bir kod parçasının genel program mimarisinde bir makro ya da fonksiyon olarak iyi bir uyum olup olmayacağına karar verir.


9
Fonksiyon çizgiselleştirmeye ne dersiniz?
Nathan Cooper

1
C dilinde & co'da bir makro da bir işlev çağrısı olabilir. Bu yüzden ikisi arasında bir ayrım yapmak pek mantıklı değil.
Sombrero Tavuk

5
Ve C tarzı makrolar kendi kendine yeten herhangi bir şey değildir - sözlü bir kapsam sunmazlar ve ikame noktasında kapsamdaki yerel isimlere sınırsız erişime sahiptirler.
Yararsız

@Sombrero Chicken: Belki de bunun bir örneğini gösterebilirsin? CONTAIN işlev çağrıları yapan makrolarınız olabilir, ancak (AFAIK) makro bir işlev çağrısı değildir.
jamesqf

3
Bu cevap hakkında yanıltıcı birçok şey var. Bahsettiğiniz örnekler kesinlikle hiçbir şekilde makroların 'tercih edilebilir' olduğu durumlar değildir - aslında tam tersi. Çok iyi bir neden olmadığı sürece makrolar bu tür şeyler için kullanılmamalıdır. Performans genellikle makroları kullanmak için iyi bir gerekçe değildir. Diğer yorumlarda belirtilen nedenlerden ötürü, makroların bu şekilde kullanılmasının gerekçelendirilmesi, özellikle daha büyük bir kod tabanında olmak üzere, her tür istenmeyen sonuçla birlikte hataya açık kodla sonuçlanabilir.
Ben Cottrell

65

Ne yazık ki, programlamada "makro" teriminin birçok farklı kullanımı vardır.

Lisp dil ​​ailesinden ve onlardan esinlenilen dillerin yanı sıra Scala ve Haskell gibi birçok modern fonksiyonel veya işlevsel ilham veren dilde ve Boo gibi bazı zorunlu dillerde, makro derleme zamanında çalışan bir kod parçasıdır (veya en azından derleyici olmayan uygulamalar için çalışma zamanından önce) ve Özet Sözdizimi Ağacı'nı (veya belirli bir dildeki eşdeğeri, örneğin Lisp'de, S-İfadeleri olurdu) derleme sırasında başka bir şeye dönüştürebilir. Örneğin, birçok Şema uygulamasında, forgövdeye birden çok çağrıya genişleyen bir makrodur. Statik olarak yazılan dillerde, makrolar genellikle tür güvenlidir, yani iyi yazılmamış kod üretemezler.

C dil ailesinde, makrolar daha çok metinsel ikame gibidir. Bu da iyi yazılmamış veya sözdizimsel olarak yasal olmayan kod üretebilecekleri anlamına gelir.

Makro birleştiricilerde, "makrolar", "sanal talimatlar" a, yani CPU'nun doğal olarak desteklemediği, ancak faydalı olduğu talimatlara atıfta bulunur ve böylece montajcı, bu talimatları kullanmanıza izin verir ve bunları CPU'nun anladığı çoklu talimatlara genişletir .

Uygulama komut dosyasında "makro", kullanıcının "kaydedebileceği" ve "oynatabileceği" bir dizi eylemi ifade eder.

Bunların hepsi bir anlamda yürütülebilir kod türleridir, yani bir anlamda işlev olarak görülebilirler. Ancak, Lisp makroları söz konusu olduğunda, bunların giriş ve çıkışları program parçalarıdır. C durumunda, giriş ve çıkışları tokenlerdir. İlk üçü de derleme zamanında yürütüldükleri çok önemli bir ayrışmaya sahiptir . Aslında, C'nin önişlemci makroları, adından da anlaşılacağı gibi, kod derleyiciye ulaşmadan önce yürütülür .


1
“Statik olarak yazılan dillerde, makrolar genellikle tür güvenlidir, yani iyi yazılmamış kod üretemezler” - gerçekten mi? Hangi dillerden bahsediyorsunuz? AFAICS, bu genelde sadece bağımlı bir dilde garanti etmek mümkündür. Haskell'de TH makroları yalnızca sözdizimsel olarak güvenlidir, ancak tür denetleyicisi daha sonra çalışır. (Yani, yazı tipi olarak, C ++ şablonlarından daha az garanti verir).
leftaroundabout

1
Uygulama komut dosyası yazma dışında, verdiğiniz üç örneğin hepsinin bu kadar farklı olduğunu düşünmüyorum. Hepsi , yürütüldüğünde paylaşılan bir kod parçasına atlamanın aksine, programa bir tür ikame gerçekleştirir.
IMSoP

Belki de C'nin makrolarından söz edilmesini M4 gibi genel makro dilleri konseptiyle genişletebilirsiniz, çünkü C için temelde spesifikasyon bir CPP yardımcı makro dili tanımlar ve C ile kullanımını standartlaştırır.
JoL

1
Genel tema, makrolar, program çalıştırıldığında yürütülmek yerine, daha büyük bir programın kaynak kodunun bir parçası olarak yorumlanacak kod üretiyor gibi görünmektedir.
jpmc26

1
@ jpmc26 Genel temanın, küçük bir şey yaptığınız ikame olduğunu ve büyük bir şeye genişlediğini söyleyebilirim. M4 makro dili özellikle kod amaçlı değildir. Herhangi bir metin oluşturmak için kullanabilirsiniz. Bu cevap gibi klavye makroları da var. 1 veya 2 tuşuna basarsanız daha fazla tuşa basabilirsiniz. vim makroları da böyledir. Tek bir tuşun altında büyük bir normal mod komut dizisini kaydedin ve bu diziyi, onu çalıştıran normal mod komutunu çalıştırarak çağırın.
JoL

2

C dili ailesinde bir makro tanımı , bir önişlemci komutu, tanımda derlenmeden makro çağrısında değiştirilen parametreli bir kod şablonu belirtir . Bu, tüm serbest değişkenlerin makro çağrısı bağlamında bağlanması gerektiği anlamına gelir. Yan etkisi olan parametre bağımsız değişkenleri i++, parametrenin çoğul kullanımı ile tekrarlanabilir. 1 + 2Bazı parametrelerin argümanının metinsel olarak değiştirilmesi xderlemeden önce gerçekleşir ve beklenmeyen davranışlara x * 3( 7io 9) neden olabilir . Makro tanımındaki makro gövdesinde bir hata, yalnızca makro çağrısında derleme yapıldığında gösterilir.

Fonksiyon tanımlama işlevi vücut bağlamına bağlı serbest değişkenler belirtir kodu; işlev çağrısı değil .

Bununla birlikte, makro görünüşte negatiftir, çağrıya, satır numarasına ve kaynak dosyaya, dize olarak bağımsız değişkene erişim sağlar .


2

Biraz daha soyut terimlerle ifade etmek gerekirse, makro bir işlev veriye olduğu gibi sözdizimidir. Bir işlev (özette) veriler üzerinde bazı dönüşümleri kapsar. Bağımsız değişkenlerini değerlendirilmiş veri olarak alır, üzerinde bazı işlemler yapar ve aynı zamanda sadece veri olan bir sonuç döndürür.

Buna karşılık bir makro değerlendirilmemiş bir sözdizimi alır ve bu konuda çalışır. C benzeri diller için sözdizimi simge düzeyinde gelir. LISP benzeri makroları olan diller için sözdizimini AST olarak gösterirler. Makro, yeni bir sözdizimi yığını döndürmelidir.


0

Bir makro genellikle derleme veya ön işleme sırasında "çağrı" makrosunun yerini hedef dilde tek tek talimatlarla değiştirerek yerine genişletilen bir şeyi ifade eder . Çalışma zamanında, genellikle makronun nerede başlayıp nerede bittiğine dair bir gösterge olmayacaktır.

Bu, bellekte ayrı olarak bulunan ve kontrolün çalışma zamanında geçirildiği yeniden kullanılabilir bir kod parçası olan bir alt rutinden farklıdır . Çoğu programlama dilinde "fonksiyonlar", "prosedürler" ve "yöntemler" bu kategoriye girer.

Olarak Jörg W MITTAG cevabı anlatılır tam detayları diller arasında değişir: bir de, örneğin, C, kaynak kodunda makro gerçekleştirdiği metin ikame gibidir; Lisp gibi bazılarında, Soyut Sözdizimi Ağacı gibi bir ara formun manipülasyonunu gerçekleştirir. Bazı gri alanlar da vardır: bazı diller "satır içi işlevler" için bir işlev gibi tanımlanmış, ancak bir makro gibi derlenmiş programa genişletilmiştir.

Çoğu dil, programcıları her bir alt program hakkında tek başına akıl yürütmeye, girişler ve çıkışlar için tür sözleşmeleri tanımlamaya ve arama kodu hakkında diğer bilgileri gizlemeye teşvik eder. Çoğu zaman, makroların oluşturmadığı bir alt programı çağırmak için bir performans etkisi vardır ve makrolar, programı bir alt programın yapamayacağı şekillerde değiştirebilir. Bu nedenle makrolar, daha az soyut temelde çalıştıkları için alt rutinlerden "daha düşük seviye" olarak kabul edilebilir.


0

Makro derleme sırasında yürütülür ve işlev çalışma zamanında yürütülür.

Misal:

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

Derleme sırasında kod aslında şu şekilde değiştirilir:

#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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.