Rozważ ten prosty kod:
void g();
void foo()
{
volatile bool x = false;
if (x)
g();
}
Widać, że ani gcc
nie clang
optymalizuje potencjalnego połączenia z g
. W moim rozumieniu jest to poprawne: maszyna abstrakcyjna ma zakładać, że volatile
zmienne mogą się zmieniać w dowolnym momencie (z powodu np. Mapowania sprzętowego), więc ciągłe składanie false
inicjalizacji do if
sprawdzenia byłoby błędne.
Ale MSVC g
całkowicie eliminuje wezwanie do (zachowując odczyty i zapisy do volatile
tego!). Czy to zachowanie jest zgodne ze standardami?
Tło: czasami używam tego rodzaju konstrukcji, aby móc włączać / wyłączać wyjście debugowania w locie: kompilator musi zawsze odczytywać wartość z pamięci, więc zmiana tej zmiennej / pamięci podczas debugowania powinna odpowiednio zmodyfikować przepływ sterowania . Wyjście MSVC ponownie odczytuje wartość, ale ignoruje ją (prawdopodobnie ze względu na ciągłe składanie i / lub eliminację martwego kodu), co oczywiście nie zgadza się z moimi intencjami.
Edycje:
Eliminacja odczytów i zapisów
volatile
jest omawiana tutaj: Czy kompilator może zoptymalizować lokalną zmienną zmienną? (dzięki Nathan!). Myślę, że standard jest całkowicie jasny, że te odczyty i zapisy muszą się zdarzyć. Ale ta dyskusja nie obejmuje tego, czy kompilator może przyjmować wyniki tych odczytów za pewnik i optymalizować na ich podstawie. Przypuszczam, że jest to niedokreślone / nieokreślone w standardzie, ale byłbym szczęśliwy, gdyby ktoś udowodnił, że się mylę.Mogę oczywiście utworzyć
x
zmienną nielokalną, aby rozwiązać problem. To pytanie jest bardziej z ciekawości.