Önişlemci yönergesi veya if (sabit) deyimi kullanmak daha mı iyi?


10

Diyelim ki birçok farklı müşteri için kullanılan bir kod tabanımız var ve içinde sadece X tipi müşteriler için geçerli olan bir kodumuz var. Bu kodu yalnızca X tipi müşteriye dahil etmek için önişlemci direktiflerini kullanmak daha mı iyi, yoksa if ifadeleri nasıl kullanılır? Daha açık olmak gerekirse:

// some code
#if TYPE_X_COSTUMER  = 1
// do some things
#endif
// rest of the code

veya

if(TYPE_X_COSTUMER) {
    // do some things
}

Düşünebileceğim argümanlar:

  • Önişlemci yönergesi, daha az kod kapladığı alan ve daha az dal oluşturur (optimize edilmeyen derleyicilerde)
  • İfadeler her zaman derlenen kodla sonuçlanırsa, örneğin birisi üzerinde çalıştığı proje için alakasız koda zarar verecek bir hata yaparsa, hata yine de görünür ve kod tabanını bozmaz. Aksi takdirde yolsuzluğun farkında olmayacaktır.
  • Bana her zaman önişlemcinin kullanımı yerine işlemci kullanımını tercih etmem söylendi (Eğer bu bir argümansa ...)

Tercih edilen nedir - birçok farklı müşteri için bir kod tabanı hakkında konuşurken?


3
Optimize edici bir derleyici kullanarak oluşturulmamış bir yapıyı gönderme olasılığınız nedir? Ve bu gerçekleşirse, etki önemli olacak mı (özellikle de o zaman özleyeceğiniz diğer tüm optimizasyonlarla bağlamlandığında)?

@delnan - Kod, birçok farklı derleyiciye sahip birçok farklı platform için kullanılır. Ve etki ile ilgili - bazı durumlarda olabilir.
MByD

Sana bir şey tercih etmen mi söylendi? Bu, birisini tavuk sevmezken KFC'den yemek yemeye zorlamak gibidir.
sağ kanat

@WTP - hayır değildim, daha fazla bilmek istiyorum, bu yüzden gelecekte daha iyi kararlar alacağım.
MByD

İkinci örneğinizde, TYPE_X_CUSTOMERhala bir önişlemci makrosu mu?
detly

Yanıtlar:


5

Bahsetmediğin #define kullanmanın bir avantajı olduğunu düşünüyorum ve bu, komut satırında değeri ayarlayabilmenizdir (böylece, bir adım oluşturma komut dosyasından ayarlayın).

Bunun dışında genellikle makrolardan kaçınmak daha iyidir. Herhangi bir kapsam belirlemeye saygı duymazlar ve bu da sorunlara neden olabilir. Sadece çok aptal derleyiciler bir durumu derleme zamanı sabitine göre optimize edemezler. Bunun ürününüz için bir endişe olup olmadığını bilmiyorum (örneğin, kodu gömülü platformlarda küçük tutmak önemli olabilir).


Aslında bu olduğunu gömülü sistemler için
MByD

Sorun, gömülü sistemlerin genellikle eski bir derleyici kullanmasıdır (örneğin gcc 2.95 gibi).
11:58, B11овић

@VJo - GCC şanslı durumda :)
MByD

O zaman deneyin. Kullanılmayan kodu içeriyorsa ve bu dikkate değer bir boyutta ise, tanımlamaları yapın.
Tamás Szelei

Derleyici komut satırı üzerinden ayarlamak istiyorsanız, yine de kodun kendisinde bir sabit kullanır ve yalnızca # sabitine atanan değeri tanımlar.
CodesInChaos

12

Birçok soruya gelince, bu sorunun cevabı bağlıdır . Hangisinin daha iyi olduğunu söylemek yerine, birinin diğerinden daha iyi olduğu örnekleri ve hedefleri verdim.

Hem önişlemci hem de sabitin kendi kullanım yerleri vardır.

Ön işlemci durumunda, kod derleme süresinden önce kaldırılır. Bu nedenle, kodun derlenmemesi beklenen durumlar için en uygun yöntemdir . Bu modül yapısını, bağımlılıkları etkileyebilir ve performans yönleri için en iyi kod segmentlerinin seçilmesine izin verebilir. Aşağıdaki durumlarda, kod yalnızca önişlemci kullanılarak bölünmelidir.

  1. Çok platformlu kod:
    Örneğin, kod farklı platformlar altında derlendiğinde, kodun belirli işletim sistemi sürüm numaralarına (veya derleyici sürümüne) bağımlı olması durumunda (bu çok nadir olsa da). Örneğin, küçük endien büyük endien kod muadilleriyle uğraşırken - sabitler yerine ön işlemcilerle ayrılmalıdır. Veya Windows için kod derliyorsanız Linux ve belirli sistem çağrıları çok farklıdır.

  2. Deneysel Yamalar:
    Bunun haklı gösterilmesinin bir başka örneği, riskli olan bazı deneysel kodlar veya atlanması gereken bazı önemli modüller ve önemli bağlantı veya performans farkı olacaktır. Birinin if () altında saklanmak yerine önişlemci aracılığıyla devre dışı bırakmak istemesinin nedeni , bu özel değişiklik kümesi tarafından tanıtılan hatalardan emin olamayacağımız ve deneysel olarak çalıştığımızdır. Başarısız olursa, bu kodu yeniden yazmaktan ziyade üretimde devre dışı bırakmaktan başka bir şey yapmamalıyız. Bir süre kodun tamamını yorumlamak için idealdir .#if 0

  3. Bağımlılıklarla başa çıkmak: Oluşturmak
    isteyebileceğiniz başka bir neden Örneğin, JPEG görüntülerini desteklemek istemiyorsanız, bu modülü / saplamayı derlemekten kurtulmanıza yardımcı olabilirsiniz ve sonunda kütüphane buna (statik veya dinamik olarak) bağlanmaz modülü. Bazen paketler ./configurebu bağımlılığın kullanılabilirliğini belirlemek için çalışır ve kütüphaneler yoksa (veya kullanıcı etkinleştirmek istemiyorsa), bu tür bir işlevsellik bu kütüphaneye bağlanmadan otomatik olarak devre dışı bırakılır. Burada bu direktiflerin otomatik olarak oluşturulması her zaman faydalıdır.

  4. Lisanslama:
    Önişlemci direktifinin çok ilginç bir örneği ffmpeg'dir . Potansiyel olarak kullanımıyla patentleri ihlal edebilecek kodeklere sahiptir. Kaynağı indirir ve yüklemek için derlerseniz, bu tür şeyleri isteyip istemediğinizi sorar. Koşullar sizi mahkemeye götürebilirse, bazı durumlarda kodları gizli tutmak !

  5. Kod kopyala-yapıştır:
    Aka makroları. Bu makroların aşırı kullanımı için bir tavsiye değildir - sadece makroların geçmiş kopya eşdeğerini uygulamak için çok daha güçlü bir yolu vardır . Ancak büyük bir dikkatle kullanın; ve ne yaptığınızı biliyorsanız kullanın. Sabitler elbette bunu yapamazlar. Ama inlineeğer kolaysa fonksiyonlar da kullanılabilir .

Peki sabitleri ne zaman kullanıyorsunuz?
Neredeyse her yerde.

  1. Daha temiz kod akışı:
    Genel olarak, sabitleri kullandığınızda, normal değişkenlerden neredeyse ayırt edilemez ve bu nedenle daha iyi okunabilir koddur. Eğer #ifdef ile her 10 satır sonra 3 veya 4 hatları var Lines 75 olan rutin yazarsanız okunması ÇOK yapamaz . Muhtemelen #ifdef tarafından yönetilen bir birincil sabit verildi ve onu her yerde doğal bir akışta kullanın.

  2. İyi girintili kod: Tüm önişlemci yönergesi, başka şekilde iyi girintili kodla asla iyi çalışmaz . Bile senin derleyici #def girintilemesini izin vermez, Ön ANSI C önişlemci bir çizgi ve "#" karakteri başlangıcı arasındaki alanı için izin vermedi; baştaki "#" her zaman ilk sütuna yerleştirilmelidir.

  3. Konfigürasyon:
    Sabitlerin / veya değişkenlerin anlamlı olmasının bir başka nedeni, bunların globallere bağlanmaktan veya gelecekte konfigürasyon dosyalarından türetilecek şekilde genişletilebileceğidir.

Son bir şey:
Hiç KULLANIMI önişlemci direktifleri #ifdefile #endif kapsamını geçerken ya { ... }. yani farklı taraflarının başlangıcı #ifdefveya sonu . Bu son derece kötü; kafa karıştırıcı olabilir, bazen tehlikeli olabilir.#endif{ ... }

Bu elbette, kapsamlı bir liste değildir, ancak hangi yöntemin kullanılmaya daha uygun olduğu konusunda size kesin bir fark gösterir. Bu ilgili değil Hangisi daha iyi yerine her zaman daha fazladır arasında, hangisinin daha doğal verilen bağlamda kullanmak.


Uzun ve ayrıntılı cevap için teşekkürler. Bahsettiğiniz şeylerin çoğunun farkındaydım ve soru önişlemci yeteneklerinin kullanılıp kullanılmayacağı değil, belirli bir kullanım türü hakkında olduğu için sorudan çıkarıldılar. Ama bence sizin ifade ettiğiniz temel nokta doğru.
MByD

1
"#İfdef için #ifdef kapsamını geçmek için asla önişlemci yönergeleri KULLANMAYIN veya {...}" IDE'ye bağlıdır. IDE etkin olmayan önişlemciyi bloke edip daraltırsa veya farklı renklerle gösterirse, kafa karıştırıcı değildir.
Abyx

@Abyx, IDE'nin yardımcı olabileceği doğrudur. Bununla birlikte, insanların * nix (linux vb.) Platformu altında geliştiği birçok durumda - editörlerin seçimi vb. Çoktur (VI, emacs vb.). Yani bir başkası sizinkinden farklı bir editör kullanıyor olabilir.
Dipan Mehta

4

Müşterilerinizin kodunuza erişimi var mı? Evet ise, önişlemci daha iyi bir seçenek olabilir. Benzer bir şeyimiz var ve çeşitli müşteri (veya müşteriye özgü özellikler) için derleme zaman bayraklarını kullanıyoruz. Daha sonra bir komut dosyası müşteriye özel kodu çıkarabilir ve bu kodu göndeririz. Müşteriler diğer müşterilerin veya müşteriye özgü diğer özelliklerin farkında değildir.


3

Söylemeye değer birkaç ek nokta:

  1. Derleyici, ön işlemcinin yapamadığı bazı sabit ifadeleri işleyebilir. Örneğin, önişlemci genellikle sizeof()ilkel olmayan tipler üzerinde değerlendirme yapamaz. Bu, if()bazı durumlarda kullanımını zorlayabilir .

  2. Derleyici, atlanan koddaki sözdizimi sorunlarının çoğunu yok sayar #if(ön işlemciyle ilgili bazı sorunlar hala soruna neden olabilir), ancak atlanan kod için sözdizimsel doğruluk konusunda ısrar eder if(). Bu nedenle, bazı derlemeler için atlanan ancak diğerleri dışındaki kodlar dosyanın başka bir yerinde (örneğin yeniden adlandırılmış tanımlayıcılar) değişikliklerin bir sonucu olarak geçersiz hale gelirse, devre dışı bırakılmışsa genellikle devre dışı bırakılırsa tüm yapılarda göz ardı if()edilir #if. Kodun neden atlandığına bağlı olarak, bu iyi bir şey olabilir veya olmayabilir.

  3. Bazı derleyiciler erişilemeyen kodu atlayacak, diğerleri yapamayacak; ancak, dize değişmez değerleri dahil, erişilemeyen kod içindeki statik depolama süresi bildirimleri, hiçbir kod bu şekilde ayrılan alanı kullanmasa bile alan ayırabilir.

  4. Makrolar kendi if()içlerinde testleri kullanabilir , ancak ön işlemcinin bir makro içinde herhangi bir koşullu mantık gerçekleştirmesi için bir mekanizma yoktur [makrolarda kullanım için ? :operatörün genellikle daha iyi olabileceğini if, ancak aynı prensiplerin geçerli olduğunu unutmayın].

  5. #ifYönergesi tanımlanmış olsun neyi makro kontrol etmek için kullanılabilir.

if()Derleyicinin ne kullandığına veya hangi makroların tanımlanacağına bağlı olarak karar vermeyi içerenler dışında çoğu durumda genellikle daha temiz olduğunu düşünüyorum ; #ifBununla birlikte, yukarıdaki sorunların bazıları ifdaha temiz göründüğü durumlarda bile kullanımını gerektirebilir .


1

Uzun lafın kısası: önişlemci direktifleri hakkındaki korkular temelde 2, çoklu kapanımlar ve belki daha az okunabilir kod ve daha kriptik bir mantık.

Projeniz gelecek için neredeyse hiç büyük planı olmayan küçükse, her iki seçeneğin de artıları ve eksileri arasında aynı oranı sunduğunu düşünüyorum, ancak projeniz çok büyük olacaksa, ayrı bir başlık dosyasının yazılması gibi başka bir şey düşünün. yine de önişlemci yönergeleri kullanmak istiyorsunuz, ancak bu tür bir yaklaşımın genellikle kodu daha az okunabilir hale getirdiğini ve bu sabitlerin adının programın iş mantığı için bir şey ifade ettiğinden emin olun.


Bu harika bir kod tabanıdır ve tanımlar aslında bazı ayrı başlıklardadır.
MByD
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.