Soru C ön işlemcisi: #warning'de makroyu genişlet


#Warning yönergesinde bir makro değeri (makroyu genişlet) basmak istiyorum.

Örneğin, kod için:

#define AAA 17
#warning AAA = ???

İstenen derleme zamanı çıkışı olurdu

warning: AAA = 17

Ne için kullanıyorum ???, veya kodu nasıl artırabilirim?


32
2017-09-28 09:35


Menşei


1999'dan beri C standardına göre, sadece #error böyle bir şey için ve herhangi bir makroyu genişletmez, sadece metni tam anlamıyla yazdırır ve derlemenin durmasına neden olur. Bununla ne yapmaya çalışıyorsun? - Alexey Frunze
Hedef parametrelerine bağlı olarak AAA'yı çeşitli şekillerde tanımlayan birçok makaile sahip bir hiyerarşim var. Tanımın hedef için doğru olduğunu doğrulamak istiyorum. Ve #if AAA = 1 ... #warning "1" listesi oluşturmak istemezdim ... - elomage
Ayrıca, bu, gömülü dünya için hiçbir görüntü içermiyor, bu yüzden printf (#AAA) gibi bir şey ekleyerek makro değerini kolayca test edemiyorum; ve çalışma zamanında kontrol edin. - elomage
Yani yaparsın #if A == 1\#error A = 1\#elif A == 2\#error A = 2\#endif. - Alexey Frunze
@AlexeyFrunze Bu tam olarak önlemek istediğim şey - yukarıdaki yorumuma bakın. Tüm olası değerleri bilmem ya da çok fazla olabilir. - elomage


Cevaplar:


Önişlemci direktifini kullanabilirsiniz #pragma message.

Örnek:

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#define AAA 123
#pragma message "content of AAA: " STR(AAA)

int main() { return 0; }

Çıkış şöyle görünebilir:

$ gcc test.c
test.c:5:9: note: #pragma message: content of AAA: 123
 #pragma message("content of AAA: " STR(AAA))
         ^

Referans için:


40
2017-09-28 10:22



Bunun işe yaradığı derleyiciden (lerden) bahsetmelisiniz. #pragma's uygulamaya özgüdür. - Alexey Frunze
Gcc sürüm 4.5.3 ile çalışır (GNU GCC yamalı mspgcc-20110716), teşekkürler. - elomage
kullandığınızdan emin olun #pragma message yerine #message veya #warning - fantastory
Bu harika bir başlangıçtır ... ama bu, makronun genişlemesini basmaya değmez, değer değil. Uzun süreli (ancak basit) bir matematiğe, yani diğer makrolara göre ardışık olarak genişleyen bir makronuz varsa, bu büyük olasılıkla size pek yardımcı olmaz. - Cheetah
Eğer güzel olurdu #pragma message uyarı oluşturulmasına izin verildi. #pragma GCC diagnostic warning "message " izin vermez (gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html). - pevik


#Warning'i kullanmamanızı tavsiye ederim çünkü bu standart C değil. Ayrıca, karşı koymak istediğiniz bir hata var mı? Uyarılar genellikle derleyicinin, tamamen tehlikeli olan ancak C standardı tarafından izin verilen şüpheli bir şey yaptığınızda kullandığı bir şeydir. Normal uygulamada böyle bir durumunuz yok, bunu ya kusursuz bir şekilde derlemeyi ya da hiç istememenizi isteyeceksiniz. Bu yüzden standart #error ve standart olmayan #warning kullanacağım.

Ön işlemci tanımının gerçek içeriğini yazamazsınız. Bunun gibi bir şey yeterli olabilir:

#if (AAA < SOMETHING) && (AAA > SOMETHING_ELSE)
  #error AAA is bad.
#endif

Bu programcı için yeterince ayrıntılı olduğunu düşünüyorum. Ancak, eğer Gerçekten mi daha fazla ayrıntı ister ve modern bir C derleyiciniz var, kullanabilirsiniz static_assert. Sonra ne istediğine yakın bir şey başarabilirsin:

#include <assert.h>

#define xstr(s) str(s)
#define str(s) #s
#define err_msg(x) #x " is " xstr(x)

#define AAA 17

static_assert(AAA != 17, err_msg(AAA));

Bu makro karışıklık AAA yazdırmalıdır 17. Bu makroların nasıl çalıştığı hakkında bir açıklama bulunabilir İşte.

Static_assert'in C99 veya C11'e dahil olup olmadığından emin değilim, kesinlikle C11'de. Bunu etkinleştirmek için bazı GCC uzantılarını kullanmanız gerekebilir.


7
2017-09-28 11:26



Ayrıca bakınız bu soru C'deki statik iddialar için - moooeeeep
Sadece bir global iç parametrenin belirli bir durum için yanlış olduğunu düşündüğümüzü doğrulamak için değer ile bilgilendirici bir mesaja ihtiyacım vardı. Burada "kötü" değerler yok. Yanlış olduğu ortaya çıktı. Ama static_assert için teşekkürler, -std = c ++ 0x seçeneği ile g ++ sürüm 4.3 beri çalışır ve gcc sürüm 4.6 seçeneği olmadan _Static_assert için aliased static_assert vardır. - elomage
@elomage _Static_assert, C11’den beri C’de bir anahtar sözcüktür. <assert.h>, _Static_assert öğesine genişleyen bir makro statik_assert içerir. Her iki form da standart olduğu için kullanmak için iyi olmalıdır. - Lundin


Gerçekten bir uyarı vermek istiyorsanız, aşağıdakiler de işe yarayacaktır. Ancak, C99'un etkinleştirilmiş olmasına bağlıdır (gcc 4.8.2 veya üstü ile çalışır, daha eski sürümlerde test edilmez):

#define N 77

#define __STRINGIFY(TEXT) #TEXT
#define __WARNING(TEXT) __STRINGIFY(GCC warning TEXT)
#define WARNING(VALUE) __WARNING(__STRINGIFY(N = VALUE))

#if N == 77
_Pragma (WARNING(N))
#endif

7
2018-03-27 10:58





Çoğu zaman Makefile'im istenen tanımları içeren bir yerel generate.h dosyası oluşturur.

created.h: Makefile
        echo> generated.h "// UYARI: oluşturulan dosya. Makefile yerine değiştirin"
        date >> generated.h '+ //% Y-% m-% d% H:% M:% S üzerinde oluşturuldu
        echo >> generated.h "#if AAA == AAA_bad"
        echo >> generated.h "#warning \" AAA = $ (AAA_bad) \ ""
        echo >> generated.h "#endif"

#İnclude "generated.h" için ihtiyaç açıktır.

Doğal olarak, burada herhangi bir karmaşıklığı dönüştürebilirsiniz, ancak birkaç satırdan daha fazla alırsa Karmaşık Makefiles'in korkunç olabileceği için karmaşıklığı ayrı bir senaryoya koymak istiyorum bakım sorunu. Küçük bir Hayal gücüyle, küçük bir girdiden çok sayıda test üreten döngülere sahip olabilirsiniz.

Created.h target'in Makefile'ye bağlı olması, target.tr'deki talimatların değişmesi durumunda, generate.h'nin yeniden sağlanması için kritik öneme sahiptir. Bağımlılık listesinde de olacak ayrı bir generate.sh betiğiniz varsa.

Yasal Uyarı: Gerçek için test edilmemiştir.


2
2017-09-28 10:22