2013-06-09 17 views
15

W językach C-podobnych, jesteśmy przyzwyczajeni do if podobne do następujących:w jaki sposób C-jak kompilator interpretować if

if(x == 5) { 
    //do something 
} 
else if(x == 7) { 
    //do something else 
} 
else if(x == 9) { 
    //do something else 
} else { 
    //do something else 
} 

Moje pytanie brzmi, czy kompilator zobaczyć, że if w ten sposób, czy też w końcu jest interpretowany jak:

if(x == 5) { 
    //do something 
} 
else { 
    if(x == 7) { 
     //do something 
    } 
    else { 
     if(x == 9) { 
      //do something 
     } 
     else { 
      //do something else 
     } 
    } 
} 

EDIT: zdałem sobie sprawę, że choć pytanie ma sens w mojej głowie, to prawdopodobnie brzmiał raczej głupi do reszty populacji ogólnej. Chodzi mi bardziej o to, jak wyglądałby AST i czy istniały jakieś specjalne przypadki AST dla instrukcji "else-if" lub czy byłby skompilowany jako blok kaskadowy if/else.

+13

Żadne z nich nie jest konwertowane na inne. Każdy jest konwertowany do formatu wewnętrznego, który jest taki sam. Jakie jest twoje praktyczne pytanie programistyczne? –

+0

Somebody pleasr wysyła kod pseudo-montażowy tego, co większość kompilatorów prawdopodobnie wyprowadza z bloku if/else. –

+1

Język C będzie kompilowany do różnych reprezentacji w zależności od celu/kompilatora/etc. – maxwellb

Odpowiedz

0

Bliżej pierwszego, ale pytanie nie pasuje dokładnie.

Po skompilowaniu programów przechodzi przez kilka etapów. Pierwszym etapem jest analiza leksykalna, następnie drugim etapem jest analiza składniowa. Analiza leksykalna analizuje tekst, oddzielając go na tokeny. Następnie analiza składniowa sprawdza strukturę programu i konstruuje abstrakcyjne drzewo składniowe (AST). Jest to podstawowa struktura składniowa tworzona podczas kompilacji.

Tak więc, jeśli instrukcje if i if-else i if-elseif-else są ostatecznie strukturami w abstrakcyjnym drzewie składni (AST) przez kompilator.

Oto strona wikipedii na ASTs: https://en.wikipedia.org/wiki/Abstract_syntax_tree

edit: I rzeczywiście, a jeśli/if else prawdopodobnie tworzy coś bliżej do drugiego wewnątrz AST. Nie jestem do końca pewien, ale nie zdziwiłbym się, gdyby był reprezentowany na podstawowym poziomie jako binarna struktura warunkowego rozgałęzienia drzewa. Jeśli chcesz dowiedzieć się więcej na ten temat, możesz przeprowadzić badania nad aspektem kompilacji teorii kompilacji.

+0

Bliżej pierwszego, bliżej drugiego, i nie jesteś pewien. To nie jest odpowiedź. – EJP

+1

To zdecydowanie odpowiedź. Nie jestem do końca pewien, w jaki sposób jest on przetwarzany, ale jego serce leży w strukturze składniowej drzewa parsowania, co jest zdecydowanie kierunkiem, do którego należy przejść, jeśli plakat chce dogłębnie poznać sposób, w jaki kompilator go obsługuje. – Nathan

16

Są one odpowiednikiem kompilatora C. Nie ma specjalnej składni else if w C. Drugie if jest po prostu kolejnym oświadczeniem if.


celu wyjaśnienia, zgodnie z normą C99, jeśli instrukcja jest zdefiniowana jako

selection-statement: 
    if (expression) statement 
    if (expression) statement else statement 
    switch (expression) statement 

i związek, Stwierdzenie to jest zdefiniowane jako

compound-statement: 
    {block-item-list(opt) } 
block-item-list: 
    block-item 
    block-item-list block-item 
block-item: 
    declaration 
    statement 

Gdy kompilator liści półki próbuje zrozumieć plik kodu źródłowego, często wykonuje następujące kroki:

  1. leksykalna analiza: włączyć kod źródłowy zwykły tekst na liście „żetonów”
  2. analizy semantycznej: analizować listę tokena i wygenerować drzewo składniowe (AST)

Drzewo jest następnie przekazywane do kompilatora middle-end (optymalizację) lub back-end (do generowania kodu maszynowego)

W twoim przypadku to if

if(x == 7) { 
    //do something else 
} else if(x == 9) { 
    //do something else 
} else { 
    //do something else 
} 

jest analizowany jako wybór-oświadczenie wewnątrz zaznaczenia-oświadczenie,

selection-stmt 
    / |  \ 
exp  stmt  stmt 
    |  |  | 
...  ... selection-stmt 
       / |  \ 
       exp  stmt stmt 
       |  |  | 
       ...  ...  ... 

a ten

if(x == 7) { 
    //do something else 
} else { 
    if(x == 9) { 
     //do something else 
    } else { 
     //do something else 
    } 
} 

jest taki sam wybór-oświadczenie wewnątrz złożonego-oświadczenie wewnątrz zaznaczenia-stwierdzeniem:

selection-stmt 
    / |  \ 
exp  stmt  stmt 
    |  |  | 
...  ... compound-stmt 
         | 
       block-item-list 
         | 
        block-item 
         | 
        stmt 
         | 
       selection-stmt 
       / |  \ 
       exp stmt stmt 
       |  |  | 
       ... ...  ... 

Więc mają różne AST. Ale nie czyni różnic w backenderze kompilatora: jak widać w AST, nie ma żadnych zmian strukturalnych.

+4

Odpowiadając na pytanie na tym poziomie, używanie nazwy akronimu AST nie jest obojętne bez wyjaśnienia, co to znaczy. – TonyK

+1

@TonyK To także nieszczera z części OP, aby oczekiwać, że odbierający będzie żywą Wikipedią. Wpisanie "AST" w Google nie powinno zaszkodzić, powinno. –

+0

** rozgałęzienia **, kolejny duży temat dla użytkowników C++ – user2384250

1

Dwa fragmenty kodu są w rzeczywistości identyczne. Można zrozumieć, dlaczego jest to prawda, że ​​realizując składni „if” jest następujący:

if <expression> 
    <block> 
else 
    <block> 

NOTE that <block> may be surrounded by curly braces if necessary. 

Więc kod rozkłada się następująco.

// if <expression> 
if (x == 5) 

// <block> begin 
{ 
    //do something 
} 
// <block> end 

// else 
else 

// <block> begin 
if(x == 7) { 
    //do something else 
} 
else if(x == 9) { 
    //do something else 
} else { 
    //do something else 
} 
// <block> end 

Teraz, jeśli umieścić nawiasy klamrowe wokół bloku do „innego”, co jest dozwolone w języku, możesz skończyć z drugiej postaci.

// if <expression> 
if (x == 5) 

// <block> begin 
{ 
    //do something 
} 
// <block> end 

// else 
else 

// <block> begin 
{ 
    if(x == 7) { 
     //do something else 
    } 
    else if(x == 9) { 
     //do something else 
    } else { 
     //do something else 
    } 
} 
// <block> end 

A jeśli to zrobić wielokrotnie dla wszystkich „jeśli else” klauzule, skończy się dokładnie swojej drugiej postaci. Te dwie części kodu są dokładnie identyczne i widziane dokładnie w ten sam sposób przez kompilator.

+1

Nie, składnia instrukcji "if" nie odnosi się do "bloków". Zobacz odpowiedź Naruila, która poprawnie przytacza faktyczną składnię. –

+1

To tylko uproszczenie, aby wyjaśnić koncepcję, bez wchodzenia w rzeczywistą gramatykę (i mącenie wód). Pomyślałem, że to pomoże mu zobaczyć duży obraz (strukturę jego kodu). – Ziffusion

12

W obu C i C++ dołączanie instrukcji do zbędnej pary {} nie zmienia semantyki programu.To stwierdzenie

a = b; 

jest równoznaczne z tym jednym

{ a = b; } 

jest równoznaczne z tym jednym

{{ a = b; }} 

i do tego jeden

{{{{{ a = b; }}}}} 

Redundant {} make absolutnym bez znaczenia dla kompilatora.

W twoim przykładzie jedyną różnicą między wersją pierwszą a drugą jest grupa zbędnych {} dodanych do tej ostatniej, tak jak to zrobiłem w powyższym przykładzie a = b. Twój nadmiarowy {} nic nie zmienia. Nie ma zauważalnej różnicy między dwiema wersjami kodu, które przedstawiłeś, co sprawia, że ​​twoje pytanie jest zasadniczo bezsensowne.

Albo wyjaśnij swoje pytanie, albo popraw kod, jeśli chcesz zapytać o coś innego.

+5

To zależy od oświadczenia. Przynajmniej w C, jeśli instrukcja zawiera * złożony literał *, tworzy obiekt, którego żywotność kończy się na końcu najbliższego otaczającego bloku. W takim przypadku dołączenie pojedynczej instrukcji z nawiasami klamrowymi * ma znaczenie. W tym konkretnym przypadku masz jednak rację, że nie ma to znaczenia, szczególnie, że podfunkcje instrukcji "if" są blokami (nawet jeśli nie są to instrukcje złożone). –

+2

Ponadto '{} tworzy nowy zakres. –

+3

@ H2CO3: Tak, ale nie ma to znaczenia w kontekście pytania. Chodzi o to, że nowy zakres jest * nadmiarowy *, jeśli nie zawiera niczego, co jest w jakiś sposób powiązane z tym nowym zakresem lub zależy od tego nowego zakresu. Nadmiarowy zakres jest całkowicie nieistotny. "Transformacja", z której korzystają OP, tworzy dokładnie to - całkowicie nieistotny, nadmiarowy zakres. Jedyną możliwością "nie-redundancji" jest tutaj to, co Keith zauważył w swoim komentarzu - na przykład złożony dosłowny w warunku "jeśli". – AnT

0

Należy zauważyć, że choć Twoja pierwsza wypowiedź jest wcięty zgodnie z „drabinki” konwencją if-else, rzeczywiście „poprawny” wcięcia dla niego, który ujawnia prawdziwą zagnieżdżania jest taka:

if(x == 5) { 
    //do something 
} else 
    if(x == 7) {    // <- this is all one big statement 
    //do something else 
    } else 
    if(x == 9) {   // <- so is this 
     //do something else 
    } else { 
     //do something else 
    } 

wcięcie jest spacja; to nic nie znaczy dla kompilatora. To, co masz po pierwszym else jest jednym wielkim oświadczeniem if. Ponieważ jest to tylko jedna instrukcja, nie wymaga żadnych nawiasów klamrowych. Kiedy pytasz: "czy kompilator czyta to w ten sposób", musisz pamiętać, że większość przestrzeni jest nieistotna; Składnia określa prawdziwe zagnieżdżenie drzewa składni.

+0

Po prostu zauważ, że chociaż to wcięcie ujawnia faktyczną strukturę, to na pewno nie polecałbym go używać. – ugoren

Powiązane problemy