Zaten tanımlanmamışsa neden yalnızca bir makro tanımlansın?


93

C kod tabanımızın tamamında, her makronun aşağıdaki şekilde tanımlandığını görüyorum:

#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#endif

#ifndef BEEPTRIM_ROLL_RATE_DEGPS
#define BEEPTRIM_ROLL_RATE_DEGPS                    0.2f
#endif

#ifndef FORCETRIMRELEASE_HOLD_TIME_MS
#define FORCETRIMRELEASE_HOLD_TIME_MS               1000.0f
#endif

#ifndef TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS       50.0f
#endif

Yalnızca makroları tanımlamak yerine bu tanımlama kontrollerini yapmanın mantığı nedir?

#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#define BEEPTRIM_ROLL_RATE_DEGPS                    0.2f
#define FORCETRIMRELEASE_HOLD_TIME_MS               1000.0f
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS       50.0f

Bu uygulamayı internette hiçbir yerde açıklayamıyorum.


6
Kodun başka bir yerindeki sabitleri değiştirmenin bu şekilde çalışması garanti edilir. Başka biri bu makrolardan birini tanımlarsa, bu dosyayı ayrıştırırken önişlemci tarafından üzerine yazılmaz.
Enzo Ferber

8
WET tasarım ilkesinin bir örneğidir.
Stark

Bir örnekle bir cevap gönderin, onu derlemeyi deneyin.
Enzo Ferber

Yanıtlar:


141

Bu, derlerken makroları geçersiz kılmanıza olanak tanır:

gcc -DMACRONAME=value

Başlık dosyasındaki tanımlar varsayılan olarak kullanılır.


51

Yorumda söylediğim gibi, şu durumu hayal edin:

foo.h

#define FOO  4

defs.h

#ifndef FOO
#define FOO 6
#endif

#ifndef BAR
#define BAR 4
#endif

bar.c

#include "foo.h"
#include "defs.h"

#include <stdio.h>

int main(void)
{
    printf("%d%d", FOO, BAR);
    return 0;
}

Yazdırılacak 44.

Ancak, koşullu ifndeforada olmasaydı, sonuç MAKRO yeniden tanımlamanın derleme uyarıları olur ve yazdırılır 64.

$ gcc -o bar bar.c
In file included from bar.c:2:0:
defs.h:1:0: warning: "FOO" redefined [enabled by default]
 #define FOO 6
 ^
In file included from bar.c:1:0:
foo.h:1:0: note: this is the location of the previous definition
 #define FOO 4
 ^

1
Bu derleyiciye özeldir. Nesne benzeri bir makroyu yeniden tanımlamak, yeniden tanımlama "aynı" olmadığı sürece yasa dışıdır (bunun için daha teknik bir şartname var, ancak burada önemli değil). Yasadışı kod, bir tanılama gerektirir ve bir tanılama yayınladıktan sonra (burada bir uyarı), derleyici, kodu uygulamaya özel sonuçlarla derlemek de dahil olmak üzere her şeyi yapmakta özgürdür.
Pete Becker

7
Aynı makro için çakışan tanımlarınız varsa , çoğu durumda uyarıyı almayı tercih etmez miydiniz ? İlk tanımı sessizce kullanmak yerine (çünkü ifdefikincisi yeniden tanımlamayı önlemek için an kullanıyor ).
Peter Cordes

@PeterCordes Çoğu zaman, #infdefs altındaki tanımlar "geri dönüş" veya "varsayılan" değerler olarak kullanılır. Temel olarak, "kullanıcı yapılandırdıysa, sorun yok. Değilse, varsayılan bir değer kullanalım."
Angew artık

@Angew: Tamam, bazı var eğer öyleyse #defineskütüphanenin ABİ parçası olan bir kütüphane başlığında, sen gerektiğini değil onları sarın #ifndef. (Veya daha iyisi, bir kullanın enum). Bunun yalnızca #ifndefbir derleme birimindeki bir şey için özel bir tanıma sahip olduğunda uygun olduğunu ancak başka bir derleme biriminde uygun olmadığını açıkça belirtmek istedim . Eğer a.cfarklı bir sırayla başlıklarını içermektedir b.c, bunlar farklı tanımlarını alabilirsiniz max(a,b)ve ile bozabilir bu tanımlardan birini max(i++, x), ancak GNU deyim-ifadesinde diğer kudreti kullanım geçiciri. En azından hala kafa karıştırıcı!
Peter Cordes

@PeterCordes Bu durumda yapmaktan hoşlandığım şey#ifdef FOO #error FOO already defined! #endif #define FOO x
Cole Johnson

17

Bağlamı bilmiyorum ama bu, kullanıcıya bu makro tanımları tarafından ayarlanan değerleri geçersiz kılmak için kullanılabilirlik vermek için kullanılabilir. Kullanıcı bu makrolardan herhangi biri için açıkça farklı bir değer tanımlarsa, burada kullanılan değerlerin yerine bu değer kullanılacaktır.

Örneğin g ++ 'da, -Dderleme sırasında bir makroya bir değer iletmek için bayrağı kullanabilirsiniz .


14

Bu, başlık dosyasının kullanıcısının kendi kodundaki veya derleyicinin -D bayrağındaki tanımları geçersiz kılabilmesi için yapılır.


7

Herhangi bir C projesi birden çok kaynak dosyada bulunur. Tek bir kaynak dosyası üzerinde çalışırken, kontrollerin (ve aslında) bir anlamı yokmuş gibi görünür, ancak büyük bir C projesi üzerinde çalışırken, bir sabiti tanımlamadan önce mevcut tanımları kontrol etmek iyi bir uygulamadır. Fikir basit: o belirli kaynak dosyada sabite ihtiyacınız var, ancak başka bir dosyada zaten tanımlanmış olabilir.


2

Kullanıcıya, kullanıcının derlemesine ve üzerinde çalışmasına izin veren varsayılan bir ön ayar veren bir çerçeve / kitaplık düşünebilirsiniz. Bu tanımlar farklı dosyalara yayılır ve son kullanıcıya, değerlerini yapılandırabileceği config.h dosyasını dahil etmesi önerilir. Kullanıcı tanımlamayı unutursa, sistem ön ayar nedeniyle çalışmaya devam edebilir.


1

Kullanma

#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#endif

kullanıcının komut satırı argümanını (gcc / clang / VS'de) kullanarak makronun değerini tanımlamasına izin verir -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f.

Başka önemli bir sebep daha var. Bir önişlemci makrosunu farklı şekilde yeniden tanımlamak bir hatadır. Başka bir SO sorusuna verilen bu cevaba bakın . Denetim olmadan, derleyici çağrısında komut satırı argümanı olarak kullanılırsa #ifndefderleyici bir hata üretmelidir -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f.

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.