2010-09-01 19 views
12

Używam Coverity Prevent do projektu, aby znaleźć błędy."x = ++ x" czy to jest naprawdę niezdefiniowane?

zgłasza błąd tej wypowiedzi (Nazwy zmiennych są oczywiście zmienione):

x= 
    (a>= b) ? 
    ++x: 0; 

Przesłanie brzmi: wada

EVALUATION_ORDER: W "x=(a>= b) ? ++x: 0;", "x" jest napisane w "x" (przypisanie LHS) i zapisane w "(a>= b) ? ++x: 0;", ale kolejność, w której występują efekty uboczne, jest niezdefiniowana, ponieważ nie ma pośredniego punktu sekwencji. KONIEC ZGŁOSZENIA

Chociaż mogę zrozumieć, że "x = x++" jest niezdefiniowany, ten jest nieco trudniejszy dla mnie. Czy to jest fałszywy pozytyw, czy nie?

+1

Tytuł twojego pytania jest mylący. Mówisz, że rozumiesz, że 'x = x ++' jest niezdefiniowane. Jednak tytuł pytania wydaje się pytać, czy zdefiniowano "x = ++ x". Czy to oznacza, że ​​nie rozumiesz, że 'x = ++ x' jest niezdefiniowane? A może twoje pytanie dotyczy sprawy z warunkowym operatorem '?:'? – AnT

+0

Przepraszamy za zamieszanie. Rozumiem, że x = x ++ jest niezdefiniowane, ale nie (czas przeszły) nie rozumie, dlaczego (i jeśli) x = ++ x było niezdefiniowane. Nie wierzyłem w to?: Było głównym zgnilizną problemu, dlatego pominąłem go (niestety, nie wyjaśniając dlaczego). Aby zachować integralność komunikatu Coverity, zachowałem go w komunikacie Coverity. Zgadzam się, że to sprawiło, że moje pytanie było trochę mylące. –

+0

Czy jest to również niezdefiniowane w przypadku JAVA? Ponieważ widzę tutaj http://www.careercup.com/question?id=13543663, a najbardziej wzniosłe ans sugeruje, że da określony wynik. – user007

Odpowiedz

28

operatora warunkowego ?: ma temperaturę sekwencji pomiędzy oceny stanu (pierwszy argument operacji) i oceny drugiego lub trzeciego argumentu operacji, ale nie ma specjalnego punktu sekwencji po oceny drugiego lub trzeciego argumentu. Oznacza to, że dwie modyfikacje x w tym przykładzie potencjalnie powodują konflikt (nie są rozdzielone przez punkt sekwencji). A więc Coverity Prevent ma rację.

Twoja wypowiedź w tym zakresie jest praktycznie równoznaczne z

a >= b ? x = ++x : x = 0; 

z tym samym problemem, jak w x = ++x.

Teraz tytuł pytania sugeruje, że nie wiesz, czy x = ++x jest niezdefiniowany. To jest rzeczywiście niezdefiniowane. Jest niezdefiniowany z tego samego powodu, gdy x = x++ jest niezdefiniowany. W skrócie, jeśli ten sam obiekt jest modyfikowany więcej niż jeden raz pomiędzy parą sąsiednich punktów sekwencji, zachowanie jest niezdefiniowane. W tym przypadku x jest modyfikowany przez przypisanie i przez ++ nie ma punktu sekwencji, aby "odizolować" te modyfikacje od siebie. Tak więc zachowanie jest niezdefiniowane. Nie ma absolutnie żadnej różnicy między ++x i x++ w tym zakresie.

+0

+1: Jestem zaskoczony, dlaczego Comeau Online nie podaje błędu w tym przypadku ani w prostym przypadku "x = x ++"; – Chubsdad

+0

@chubsdad: Nie pamiętam, aby Comeau Online łapało takie sytuacje. GCC wydaje ostrzeżenia w takich przypadkach, ale nie narzeka na przypadek "?:". – AnT

+0

Czy jest to również niezdefiniowane w przypadku JAVA? Ponieważ widzę tutaj http://www.careercup.com/question?id=13543663, a najbardziej wzniosłe ans sugeruje, że da określony wynik. – user007

12

Bez względu na dokładność komunikatu, zastąpienie danego kodu przez x= (a>= b) ? x+1: 0; osiąga ten sam koniec bez żadnych nieporozumień. Jeśli narzędzie jest zdezorientowane, być może następna osoba, która przyjrzy się temu kodowi, też będzie.

Zakłada się, że x nie ma przeciążonego operatora inkrementacji z efektami ubocznymi, na których można polegać.

+0

I proszę, z dobroci serca dla innych programistów, proszę nie nazywać rzeczy 'x',' a' i 'b'. –

+0

@Dominic: pytanie wyraźnie stwierdza, że ​​nazwy, w których zmieniły się od oryginalnych nazw. –

+0

@ Joachim - ach, tęskniłem za tym, uff! –

8

Oświadczenie x = ++x; zapisuje dwukrotnie do zmiennej x przed naciśnięciem klawisza sequence point i dlatego zachowanie jest niezdefiniowane.

3

Trudno wyobrazić sobie kompilator generujący kod dla "x = ++ x;" która w rzeczywistości nie działałaby tak samo jak "++ x".Jeśli x nie jest niestabilny, byłoby prawnie, że kompilator przetworzy instrukcję "y = ++ x;" jako

 
    y=x+1; 
    x=x+1; 

Instrukcja "x = ++ x;" by w ten sposób stać się

 
    x=x+1; 
    x=x+1; 

przypadku konieczności przeznaczenia jednego wyrażenia arytmetycznego zadanie przyzwyczaić się zbyt szybko, jako argumentu źródłowego innego spowodowałoby opóźnienie rurociągu, byłego optymalizacja może być uzasadnione. Oczywiście katastrofalne, jeśli zmienna inkrementowana i przypisana to jedna i ta sama.

Jeśli zmienna "x" jest niestabilna, nie mogę wymyślić żadnej sekwencji kodu, w której kompilator, który nie byłby celowo próbujący być złośliwym, mógł zgodnie z prawem uznać "x = x ++;" jako posiadające jakikolwiek inny efekt niż odczytanie wszystkich części "x" dokładnie raz i wpisanie tej samej poprawnej wartości do wszystkich części "x" dokładnie dwa razy.

0

Przypuszczam, że logicznie, jeśli napiszesz "x = ++ x" lub "x = x ++", tak czy inaczej oczekuje się, że wynik końcowy będzie taki, że x jest o jeden więcej niż początkowo. Ale spraw, żeby był odrobinę bardziej skomplikowany. Co jeśli napisałeś "x = x + (++ x)"? Czy to jest to samo co "x = x + (x + 1)"? Czy możemy dodać jeden pierwszy, a następnie dodać x do siebie, tj. "X = (x + 1) + (x + 1)"? Co jeśli napisaliśmy "x = (x -) + (x ++)"?

Nawet gdybyś mógł napisać specyfikację językową, która dałaby jednoznaczny sens takim konstrukcjom, i mogłaby wtedy wdrożyć ją w czysty sposób, dlaczego miałbyś chcieć? Umieszczenie jednostajnego przyrostu przypisania do tej samej zmiennej po prostu nie ma sensu, a nawet jeśli zmusiliśmy go do tego, nie zapewnia on żadnej użytecznej funkcjonalności. Jestem pewien, że możemy napisać kompilator, który przyjmie wyrażenie takie jak "x + 1 = y-1" i odkryje, że to naprawdę oznacza "x = y-2", ale po co zawracać sobie głowę? Nie ma zysku.

Nawet jeśli pisaliśmy kompilatory, które zrobiły coś przewidywalnego z "x = x ++ - ++ x", programiści musieliby znać i rozumieć zasady. Bez żadnych oczywistych korzyści, po prostu zwiększyłoby to złożoność programów bez żadnego celu.

0

Aby to zrozumieć, musisz mieć podstawową wiedzę na temat punktów sekwencyjnych. Zobacz ten link: http://en.wikipedia.org/wiki/Sequence_point

Dla operatora = nie ma punktu sekwencji, więc nie ma gwarancji, że wartość x zostanie zmodyfikowana przed ponownym przypisaniem do x.

Powiązane problemy