Semantyka wyrażeń

Wyrażenia są oceniane zgodnie z pierwszeństwem i grupowaniem ich operatorów. (Pierwszeństwo operatorów i kojarzenie w konwencjach leksykalnych, pokazuje relacje operatorów języka C++ nakładanych na wyrażenia).

Kolejność obliczania

Rozważ taki przykład:

// Order_of_Evaluation.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
    int a = 2, b = 4, c = 9;

    cout << a + b * c << "\n";
    cout << a + (b * c) << "\n";
    cout << (a + b) * c << "\n";
}
38
38
54

Diagram of evaluation order in an expression.
Kolejność obliczania wyrażeń

Kolejność, w jakiej wyrażenie pokazane na powyższej ilustracji jest obliczane, zależy od pierwszeństwa i kojarzenia operatorów:

  1. Mnożenie (*) ma najwyższy priorytet w tym wyrażeniu; w związku z tym podexpression jest obliczany b * c jako pierwszy.

  2. Dodanie (+) ma następny najwyższy priorytet, dlatego a jest dodawany do produktu i bc.

  3. Przesunięcie w lewo (<<) ma najniższy priorytet w wyrażeniu, ale istnieją dwa wystąpienia. Ze względu na to, że operator lewej zmiany grupuje od lewej do prawej, lewe podwyrażanie jest oceniane jako pierwsze, a następnie prawe.

Gdy nawiasy są używane do grupowania podwyrażeń, zmieniają pierwszeństwo, a także kolejność obliczania wyrażenia, jak pokazano na poniższej ilustracji.

Evaluation order of expression with parentheses.
Kolejność obliczania wyrażeń z nawiasami

Wyrażenia, takie jak te na powyższej ilustracji, są oceniane wyłącznie pod kątem ich skutków ubocznych — w tym przypadku w celu przekazania informacji do standardowego urządzenia wyjściowego.

Notacja w wyrażeniach

Język C++ określa pewne zgodność podczas określania operandów. W poniższej tabeli przedstawiono typy operandów akceptowalne dla operatorów, które wymagają operandów typu.

Typy operandów akceptowalne dla operatorów

Oczekiwano typu Dozwolone typy
type consttype
volatiletype
typ i
consttyp i
volatiletyp i
volatile consttype
volatile consttyp i
type * type *
consttype *
volatiletype *
volatile consttype *
consttype type
consttype
consttyp i
volatiletype type
volatiletype
volatiletyp i

Ponieważ powyższe reguły mogą być zawsze używane w połączeniu, wskaźnik const do obiektu lotnego można określić, gdzie wskaźnik jest oczekiwany.

Niejednoznaczne wyrażenia

Niektóre wyrażenia są niejednoznaczne w ich znaczeniu. Te wyrażenia występują najczęściej, gdy wartość obiektu jest modyfikowana więcej niż raz w tym samym wyrażeniu. Te wyrażenia opierają się na określonej kolejności oceny, w której język nie definiuje go. Rozważmy następujący przykład:

int i = 7;

func( i, ++i );

Język C++ nie gwarantuje kolejności oceniania argumentów wywołania funkcji. W związku z tym, w poprzednim przykładzie, func może otrzymać wartości 7 i 8 lub 8 i 8 dla jego parametrów, w zależności od tego, czy parametry są oceniane od lewej do prawej, czy od prawej do lewej.

Punkty sekwencji języka C++ (specyficzne dla firmy Microsoft)

Wyrażenie może modyfikować wartość obiektu tylko raz między kolejnymi „punktami sekwencji”.

Definicja języka C++ nie określa obecnie punktów sekwencji. Microsoft C++ używa tych samych punktów sekwencji co standard ANSI C dla dowolnych wyrażeń obejmujących operatory języka C i nieobejmujących przeciążonych operatorów. Gdy operatory są przeciążone, semantyka zmienia się z sekwencjonowania operatora do sekwencjonowania wywołania funkcji. Microsoft C++ używa następujących punktów sekwencji:

  • Lewy operand operatora logicznego AND (&&). Lewy operand logicznego operatora AND jest obliczany całkowicie, wraz ze wszystkimi efektami ubocznymi zakończonymi przed kontynuowaniem. Nie ma gwarancji, że zostanie obliczony odpowiedni operand operatora logicznego AND.

  • Lewy operand operatora logicznego OR (||). Lewy operand logicznego operatora OR jest obliczany całkowicie, wraz ze wszystkimi efektami ubocznymi zakończonymi przed kontynuowaniem. Nie ma gwarancji, że właściwy operand operatora logicznego OR zostanie oceniony.

  • Lewy operand operatora przecinka. Lewy operand logicznego operatora przecinka jest obliczany całkowicie, wraz ze wszystkimi efektami ubocznymi zakończonymi przed kontynuowaniem. Oba operandy operatora przecinka są obliczane zawsze.

  • Operator wywołania funkcji. Obliczane jest wyrażenie wywołania funkcji i wszystkie argumenty funkcji, włączając w to argumenty domyślne, a wszystkie efekty uboczne są zakończone przed wejściem do funkcji. Nie ma żadnej określonej kolejności obliczania między argumentami lub wyrażeniem wywołania funkcji.

  • Pierwszy operand operatora warunkowego. Pierwszy operand operatora warunkowego jest obliczany całkowicie, wraz ze wszystkimi efektami ubocznymi zakończonymi przed kontynuowaniem.

  • Koniec pełnej inicjalizacji wyrażenia, taki jak koniec inicjalizacji w instrukcji deklaracji.

  • Wyrażenie w instrukcji wyrażenia. Instrukcje wyrażeń składają się z opcjonalnego wyrażenia z następującym po nim średnikiem (;). Wyrażenie jest obliczane całkowicie ze wszystkimi efektami ubocznymi.

  • Wyrażenie kontrolujące w instrukcji wyboru (if lub switch). Wyrażenie jest obliczane całkowicie, wraz ze wszystkimi efektami ubocznymi zakończonymi przed wykonaniem kodu zależnego od wyboru.

  • Wyrażenie kontrolujące instrukcji while lub do. Wyrażenie jest obliczane całkowicie, wraz ze wszystkimi efektami ubocznymi zakończonymi przed wykonaniem dowolnej instrukcji z następnej iteracji pętli while lub do.

  • Każde z trzech wyrażeń instrukcji for. Każde wyrażenie jest obliczane całkowicie, wraz ze wszystkimi efektami ubocznymi zakończonymi przed przeniesieniem do następnego wyrażenia.

  • Wyrażenie w instrukcji return. Wyrażenie jest obliczane całkowicie, wraz ze wszystkimi efektami ubocznymi zakończonymi przed zwróceniem sterowania do funkcji wywołującej.

Zobacz też

Wyrażenia