2012-12-18 19 views
5

Kodum, derleme komutlarını, çalışma zamanını tercih etme zamanında oluşturma zamanında hataları işaretlemek ve çalışma zamanında çalışma haklarını yürütmeyerek performansı artırmak için yaygın şekilde kullanır.C derleyici şunları ifade eder: ifadenin nerede sabitlendiği her yerde dinamik olarak nasıl kullanılır?

#define COMPILER_ASSERT(EXPR) switch (0) {case 0: case (EXPR):;} 

Hepsi güzel. Aşağıdaki durum için derleyici önermeler kullanmak için bunu genişletmek istiyorum. 100 tanesi denilen bir makronun olduğunu, bunların 99'unun sabit bir değerden geçtiğini ve 1'inin bir değişkeni geçtiğini söyleyin. Makroyu, bir derleyicinin 99 yerde göstermesini sağlamak için kod yazabilirim ve bir çalışma zamanı sonuncusunu gösterir.

MY_FUNCTION() öğesinin her zaman sabit bir değerle çağrıldığını garanti edersem bunu böyle kodlayabilirim. O X'in sabittir garanti, ancak işlevim yapılan her çağrı için yararlanmak isteyen olamazsa

void my_function(int x) 
{ 
    //do something 
} 

#define MY_FUNCTION(X) \ 
    COMPILER_ASSERT(X != 0); \ 
    my_function(X) 

//These can all take advantage of a compiler assert. 
MY_FUNCTION(1); 
MY_FUNCTION(SOME_HASH_DEFINE); 
MY_FUNCTION(sizeof(SOME_STRUCTURE)); 
//This can't (this is a contrived example - actual code is complex). 
int some_variable = 1; 
MY_FUNCTION(some_variable); 

Yani,() nerede olduğunu, nasıl kod? gibi bir şey: Sadece geçmesine sabit değerlere işlevim çağrı Yeniden Kodlama

#define MY_FUNCTION(X) \ 
    if (X is a fixed value) COMPILER_ASSERT(X != 0); \ 
    else assert(X != 0); \ 
    my_function(X) 

() benim için bir seçenek değildir. Evet MY_FUNCTION_FIXED_X ve MY_FUNCTION_VARIABLE_X'i tanımlayabilirim ancak bu, tüm bunları arama koduna yansıtır. Yardımlarınız için

teşekkürler. NICKb

+1

Belki de gerçek derleme zamanı olan C11'i kullanabilirsiniz? –

+0

Sabit derken, derleme zamanı sabiti mi demek istiyorsun? Eğer evet ise, müşteri kodundaki 99 çağrıda değer farklı olabilir, doğru mu? – Anon

+0

Doğru. Bir örnek MY_FUNCTION (X) öğesine iletilen değerin belirli bir tamsayı aralığında olması gerektiği ve X'in menzil içinde olduğunu iddia etmek istiyorum. – NickB

cevap

2

C derleyicisi değişken uzunlukta diziler destekliyorsa, şöyle yazabilirsiniz:

(assert((EXPR)), (void) sizeof(char[-1])) 
: EXPR sahte değerli derleme zamanı sabiti olan

#define GENERIC_ASSERT(EXPR) \ 
    ((EXPR) ? (void) 0 : assert((EXPR)), (void) sizeof(char[(EXPR) ? 1 : -1])) 

, bu kadar azaltır Bir derleme hatası olan

(negatif uzunluklu bir diziyi içerir). EXPR gerçek değerli derleme zamanı sabiti ise

, elde ederiz:

((void) 0), (void) 1) 

Clang ve gcc Hem gerçek değerli derleme zamanı sabiti ile çağrılan eğer hiçbir şey assert azaltma yeteneğine sahiptir.

EXPR bir çalışma zamanı değeri varsa

, eğer (örneğin, bir durdurma) bir çalışma zamanı hata ile sonuçlanır çağrılan sizeof ifadesi, assert virgül operatörün kullanımı boyunca birinci dizilir.derleme zamanı sabiti durumda maalesef

, gcc tarafından hata mesajı çıktı özellikle aydınlatıcı değildir:

error: array size is negative 
    GENERIC_ASSERT(2 + 2 == 5); 
    ^~~~~~~~~~~~~~~~~~~~~~~~~~ 
note: expanded from: 
    ((EXPR) ? (void) 0 : assert((EXPR)), (void) sizeof(char[(EXPR) ? 1 : -1])) 
                  ^~~~~~~~~~~~~~~ 
+0

Bunun peşinde olduğumu düşünmüyorum. Bir derleyicide derlenecek bir şey olup olmadığını ifade edersem, ifade değiştiyse ve yalnızca bir çalışma zamanı derlemesi değişkenin değiştiğini iddia ederse, bu nedenle derlenen herhangi bir sonuçtan derlenen yürütülebilir koddan elimine ederek en iyi çalışma zamanı performansını verir. zaman. – NickB

+0

@NickB, 'EXPR' bir derleme zamanı sabiti ise, 'assert' erişilemeyen bir daldadır ('EXPR' true, '(void) 0' dalı alındığı için) boş bir deyim. – ecatmur

0

nasıl bu konuda: Clang yılında

prog.c:5: error: size of array ‘type name’ is negative 

biraz daha iyi

#define MY_FUNCTION(X) \ 
    do{ \ 
if (X>=1 && X<=20) {\ 
COMPILER_ASSERT(X != 0); \ 
my_function(X);\ 
}\ // end if block 
    // you can use break here too 
    else myfunction2(X,__FILE__,__LINE__); \ // this will be the runtime assert 
}while (0); 


void myfunction2(int x, const char * file, const int line) 
{ 
// print here information 
exit(-1); 
} 
0

P99'da bu makro statik statik değerler için var

# if p99_has_feature(c_static_assert) 
# define static_assert _Static_assert 
# else 
# define static_assert(EXPR, DIAGSTR)       \ 
extern char const p00_compiletime_assert[       \ 
sizeof((void const*[3*(!!(EXPR)) - 1]){       \ 
    &p00_compiletime_assert,          \ 
    "static assertion failed: " P99_STRINGIFY(EXPR) ", " DIAGSTR}) \ 
] 
extern char const p00_compiletime_assert[sizeof(void const*[2])]; 
# endif 
#endif 

Bu, hemen hemen her yerde kullanabileceğiniz, en azından C99 ile bir beyanın kullanılabildiği avantajı vardır. (C99 ifadeleri ve bildirimleri karıştırmaya izin verir) Yani bu, EXPR'un bir derleme zaman tamsayı sabiti olması koşuluyla, herhangi bir türde bir işlev bloğu içinde veya dosya kapsamı içinde kullanılabilir.