2013-05-17 35 views
7

i'v następnym kod:jest Pierwszeństwo operatora ignorowane 'czy' warunki

void main() 
{ 
    int k, x, y, z; 
    printf("\nExperiment 1:"); 
    x = 0, y = 0, z = 0; 
    k = x++ || y++ && z++; 
    printf("\nx = %d, y = %d, z = %d and k = %d\n", x, y, z, k); 
    printf("\nExperiment 2:"); 
    x = 1, y = 0, z = 0; 
    k = x++ || y++ && z++; 
    printf("\nx = %d, y = %d, z = %d and k = %d\n", x, y, z, k); 
} 

Wydajność:

Eksperyment 1: x = 1, y = 1, Z = 0 i k = 0

Eksperyment 2: x = 2, y = 0, z = 0 i k = 1

Co mam rozumieć to: dla ekspresji aby mogło być prawdziwe, albo lewa lub prawa strona "||" musi być niezerowe. Zaczyna się od lewej. Jeśli pozostanie niezerowe, nie ocenia dalej. Jeśli jest zero, zaczyna się po prawej stronie. Po prawej mamy "& &". Tak więc, ponownie zaczynamy od lewej strony & &, a jeśli jest zero, wyrażenie nie może być prawdziwe i nie jest kontynuowane. Inaczej ocenia prawą stronę „& &”

Moim założeniem było operator & & ma wyższy priorytet. Tak więc oba argumenty należało ocenić, a następnie zastosować do niego & &, a następnie ocenić oba argumenty ||.

Czy optymalizuje się sam kompilator? Użyłem funkcji Visual Studio TC compilar z wyłączoną Optymalizacją.

+5

Nie są to "jeśli warunki", przy okazji. Są po prostu wyrażeń, używając operatorów boolowskich i operatorów po inkrementacji. – unwind

+3

Tylko dlatego, że && ma zaostrzone pierwszeństwo, nie oznacza 'k = x ++ || (y ++ && z ++) 'wykona polecenie && przed ||. Nazywa się to zwarciem i jest bardzo dobrze znane. Wspomniałeś o tym nawet sam. Wyobraź sobie: 'k = x ++ || f (& y, & z) 'gdzie f() zwraca' (* y) ++ && (* z) ++ '. Jest to funkcjonalnie równoważne z twoim kodem. – Matthias

+0

@Matthias: rzeczywiście; '++' ma jeszcze wyższy priorytet niż '&&'; nie oczekujemy, że post-inkrementacja stanie się przed wszystkim innym tylko ze względu na pierwszeństwo ... – geoffspear

Odpowiedz

9

myślę, że to jest pokryta C11 przez §6.5.14 Logical OR operator (moje podkreślenie)

przeciwieństwie do bitowe | operator, the || operator gwarantuje ocenę od lewej do prawej; jeśli oceniany jest drugi argument, istnieje punkt sekwencji między ocenami pierwszego i drugiego argumentu . Jeśli pierwszy operand jest nierównomierny do 0, drugi operand nie jest oceniany.

4

Więc wyrażenie

k = x++ || y++ && z++; 

jest interpretowane jako (ze względu na precendence zasad):

k = x++ || (y++ && z++); 

W experiement 1, mamy x = y = z = 0;.

W wersji eksperymentalnej 2 mamy x = 1, y = z = 0;.

Wyrażenie po prawej stronie zatrzymuje się po przeprowadzeniu oceny y++, ponieważ wartość ta wynosi 0, a zatem wartość logiczna i nie może być prawdziwa.