2009-11-03 11 views
11

Właśnie zauważyłem, że biorąc pod uwagę następujący kod:Magia kompilatora: dlaczego?

if (x.ID > 0 && !x.IsCool) 

Microsoft C# 3.0 (VS2008 SP1) kompilator zoptymalizować go do tego:

if (!((x.Id <= 0) || x. IsCool)) 

Jest na Debug zbudować bez włączona Optymalizacja . Dlaczego robi to kompilator? Czy jest szybszy pod względem wykonania?

użyłem reflektor do tego dowiedzieć (I rzeczywiście, patrząc na coś innego)

+8

Jak się dowiedziałeś? –

+1

Co się dzieje z efektem pobudzającym efekt uboczny? :) –

+0

@pst: efekty uboczne na getter mogą być ignorowane przez kompilator. Zasadniczo kompilator nie może przyjmować żadnych skutków ubocznych dla modułów pobierających i ustawiających. –

Odpowiedz

49

Kompilator C# z pewnością nie generuje równoważnego kodu C# dla twojego fragmentu. Jest skompilowany do IL. Zasadniczo, to co widzisz (z Reflectora, jak sądzę) jest równoważnym kodem C#, który wypacza dekompilator dla tej IL.

  1. Specyfikacja językowa nie określa, czym jest kod "niezoptymalizowany". Kompilator C# może generować dowolny poprawny, funkcjonalnie równoważny kod. Nawet bez włączania optymalizacji kompilator może wykonywać podstawowe optymalizacje. Poza tym nie można powiedzieć, że to, co kompilator celowo zoptymalizował, czy nie jest , to czy kompilator celowo je zoptymalizował, czy nie, .

  2. Instrukcja jako całość jest traktowana jako sekwencja rozgałęzień warunkowych na podstawie wartości każdego pojedynczego wyrażenia określonego w klauzuli "i".Wyrażenie jest nie oceniane w jednym bloku kodu za pomocą instrukcji "i". Wyjście dekompilatora jest czymś wywnioskowanym z tych gałęzi. Dekompilator nie zawsze może wywnioskować oryginalne wyrażenie, które napisałeś. Po prostu wydaje coś równoważnego.

Podobnie, różnica pomiędzy tym fragmencie:

if (a) { something(); } 
else { somethingElse(); } 

i ten fragment:

if (!a) { somethingElse(); } 
else { something(); } 

nie jest coś, co można odróżnić widząc skompilowany kod.

+3

+1 To jest odpowiednia odpowiedź i zwięźle wyjaśniona do rozruchu. :) –

+1

Nie chciałem, jeśli to faktycznie jest "optymalizacja" (stąd cytaty). To jest || wartości razem, o które się zastanawiałem. Sądziłem, że IL użyje prawdziwego boolowskiego i/lub operacji, ale tak nie jest. pod maską stosowana jest tylko kombinacja ble.s, br.s i brtrue.s. –

8

Myślę, że te dwa wyrażenia są dokładnie równoważne z semantyki języka punktu widzenia. Oba sposoby obejmują zwarcie.

Jestem trochę oszołomiony, że odpowiedź Andrzeja ma już dziesięć upgotes; Brzmi to dla mnie nonsensem, ale może naprawdę brakuje mi czegoś subtelnego.

EDIT

Więc podsumowując:

pytanie PO pyta „dlaczego ta optymalizacja zdarzyć”.

Tak naprawdę nie ma "optymalizacji". Dwa kody źródłowe C# są logicznie równoważne. ".Net Reflector" lub jakiekolwiek inne narzędzie do demontażu jest prawdopodobnie tak samo zdolne do dekompilacji tego samego IL w jednym lub drugim. Na poziomie IL istnieje tylko kilka warunkowych skoków, więc niekoniecznie istnieje sposób, aby dowiedzieć się, "która droga jest, a która jest inna" lub inne podobne równoważniki DeMorgan.

Fascynująco, ludzie są szalenie szczęśliwi głosując w górę lub w dół odpowiedzi na to pytanie, nawet jeśli (a może dlatego) oryginalne pytanie nie ma większego sensu (lub opiera się na błędnym założeniu).

Na szczęście dominuje mądrość tłumów (i inteligentnych osób, takich jak @Mehrdad). Hurray dla StackOverflow!

(Robię swoją odpowiedź na wiki, ponieważ nie chcę, aby przedstawiciel był "opowiadania o pytaniu", gdy przedstawiciel powinien otrzymać "dobre odpowiedzi na pytanie", ale myślę, że historia tego pytania jest interesujące.)

+3

@Brian - Byłem oszołomiony, biorąc pod uwagę fakt, że byłem w 100% niepoprawny :) To jest to, co dostaję za wysłanie off-the-a - Nie lubię tego bez zastanowienia. –

+0

Masz całkowitą rację, różnicowanie przypadku pokazuje, że ** dokładnie takie same ** gałęzie są generowane przez oba kody, stąd te same zwarcia. Jest to jednak subtelne i na pierwszy rzut oka rzeczywiście myślałem, że Andrew miał rację (wtedy zrobiłem wszystkie przypadki w mojej głowie). –

+1

:) Cieszę się, że projekt StackOverflow (edycja, styl wiki, głosowanie) oznacza, że ​​ostatecznie wszystko działa, nawet jeśli może to być jazda rollercoasterem w ciągu pierwszych kilku minut pytania. :) – Brian

6

Jeśli kompiluje się do warunkowego kodu skoku. Podniesienie negacji z wyrażenia pozwala na jego optymalizację poprzez zamianę warunkowego celu skoku na blok przewracający.

Powiązane problemy