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
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:
Mnożenie (*) ma najwyższy priorytet w tym wyrażeniu; w związku z tym podexpression jest obliczany
b * c
jako pierwszy.Dodanie (+) ma następny najwyższy priorytet, dlatego
a
jest dodawany do produktu ib
c
.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.
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 | const typevolatile typetyp i const typ ivolatile typ ivolatile const typevolatile const typ i |
type * | type *const type *volatile type *volatile const type * |
const type |
typeconst typeconst typ i |
volatile type |
typevolatile typevolatile typ 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ż
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla