2015-08-29 18 views
6

Natknąłem się na oświadczenie w tekście C Jak programować:Co to są wyrażenia z efektami ubocznymi i dlaczego nie powinny być przekazywane do makra?

"Wyrażenia z efektami ubocznymi (tj. Zmienne wartości są modyfikowane) nie powinny być przekazywane do makra, ponieważ argumenty makr mogą być ocenione więcej niż jeden raz." .

Moje pytanie brzmi: jakie są wyrażenia z efektami ubocznymi i dlaczego nie powinny być przekazywane do makra?

+0

http://stackoverflow.com/questions/7299286/whats-the-side-effect-the-following-macro- in-cbedded-c jest dobrym przykładem. – Downvoter

Odpowiedz

8

Klasycznym przykładem jest makro obliczyć maksymalnie dwóch wartości:

#define MAX(a, b) ((a) > (b) ? (a) : (b)) 

Teraz pozwala „nazywają” makro tak:

int x = 5; 
int y = 7; 
int z = MAX(x++, y++); 

Teraz jeśli MAX było normalne funkcjonowanie, spodziewalibyśmy się, że x i y zostaną inkrementowane raz, prawda? Jednak, ponieważ jest to makro „CALL” zastępuje się następująco:

int z = ((x++) > (y++) ? (x++) : (y++)); 

Jak widać, zmienna y będzie zwiększany dwukrotnie, raz w warunku, a raz jako końcowego wyniku ternary operator.

Jest to wynik wyrażenia z efektami ubocznymi (wyrażenie po inkrementacji) i rozwinięciem makra.


W powiązanej notatce są też inne niebezpieczeństwa związane z makrami. Na przykład, weźmy to proste makro:

#define MUL_BY_TWO(x) (x * 2) 

Wygląda prosto, prawda? Ale teraz co, jeśli używamy go tak:

int result = MUL_BY_TWO(a + b); 

To rozszerzy jak

int result = (a + b * 2); 

A jak mam nadzieję, że wie, mnożenie mają wyższy priorytet niż Dodatkowo, więc wyrażenie a + b * 2 jest równoważna a + (b * 2), prawdopodobnie nie to, co zamierzał autor makr. Dlatego argumenty makra należy umieścić wewnątrz własnych nawiasach:

#define MUL_BY_TWO(x) ((x) * 2) 

Następnie ekspansja będzie

int result = ((a + b) * 2); 

który jest prawdopodobnie poprawne.

+0

rozumiem !!! thanx !!! –

1

Po prostu efektem ubocznym jest zapis do obiektu lub odczyt zmiennego obiektu.

Więc przykładem efekt uboczny:

i++; 

Oto wykorzystanie efekt uboczny w makro:

#define MAX(a, b) ((a) > (b)) ? (a) : (b)) 

int a = 42; 
int b = 1; 
int c; 

c = MAX(a, b++); 

Niebezpieczeństwo jest sprzeczne z funkcji gdzie argumenty są przekazywane według wartości potencjalnie modyfikuje się obiekt b jeden lub dwa razy (w zależności od makrowych argumentów, tutaj jeden raz) w makrze, ze względu na sposób działania makr (zastępując tokeny w definicji makra).

1

działania niepożądane mogą być zdefiniowane jako:

Ocena wyrazem produkuje coś, a jeśli w dodatku nie ma zmiany w stanie środowiska wykonawczego jest powiedziane, że wyrażenie (jego ewaluacja) ma jedne skutki uboczne). Na przykład

int x = y++; //where y is also an int 

oprócz operacji inicjalizacji, wartość Y ulega zmianie w wyniku działania bocznych ++ operatora.

Rozważmy teraz makra do kwadratury od An liczb:

#define Sq(a) a*a 
main() 
{ 
    int a=6; 
    int res=Sq(a); 
    printf("%d\n",res); 
    res=Sq(++a); 
    printf("%d",res); 
} 

Można by oczekiwać, że produkcja będzie

36 49

jednak wyjście jest

36 64

bo makro skutkuje wymianą tekstowej i

res staje (++ a) * (++ a) tj, 8 * 8 = 64

Dlatego nie powinniśmy przekazywać argumenty z efektami ubocznymi do makr. (http://ideone.com/mMPQLP)