2010-03-26 21 views
12

Rozumiem, że jedną z wielkich ofert dotyczących stałych jest to, że nie trzeba przechodzić i aktualizować kodu, w którym ta stała jest używana w każdym miejscu. To świetnie, ale załóżmy, że nie deklarujesz tego wprost jako stałą. Jakie korzyści istnieją, aby przyjąć zmienną, której HAPPENS faktycznie nie zmienia i czyni ją stałą, czy to pozwoli zaoszczędzić na przetwarzaniu i/lub rozmiarze kodu ... itd.?Zalety stałych

Zasadniczo mam program, który kompilator mówi, że konkretna zmienna nie została zmieniona, a zatem można ją zadeklarować jako stałą, po prostu chciałem wiedzieć, jaka byłaby korzyść z dodania stałego kwalifikatora do niego, jeśli to czyni nie ma różnicy, która sprawia, że ​​ta zmiana nie dodaje żadnej wartości, a zatem nie ma marnowania czasu (ten sam scenariusz występuje w więcej niż jednym miejscu) wracając i "naprawiając" wszystkie te zmienne.

+0

Wiele dobrych odpowiedzi, dziękuję, zgadzam się, że deklarując je jako stałe, istnieje korzyść w zakresie rozwoju, ale myślę, że myślę o korzyściach w czasie wykonywania, niekoniecznie kompiluje czas ... jeśli to czyni sens. – onaclov2000

+0

Korzyści dla środowiska wykonawczego zależą od konkretnego kompilatora i komputera, na którym program jest kompilowany i uruchamiany; język opisuje, jak rzeczy powinny funkcjonować, a nie w jaki sposób są wdrażane. – jball

+1

Wykrywanie błędów podczas kompilacji jest znacznie ważniejsze niż jakiekolwiek (minimalne) korzyści, które mogą być realizowane w czasie wykonywania. Zawsze możesz sprawić, by kod działał szybciej, kupując szybszy sprzęt, ale nie możesz poprawić kodu w ten sposób. A jeśli kod nie jest poprawny, nie ma sensu go uruchamiać. –

Odpowiedz

17

Jeśli zadeklarujesz zmienną jako stałą, to optymalizator często może ją wyeliminować poprzez "stałe fałdowanie", a co za tym idzie przyspieszyć twój program i zaoszczędzić miejsce. Na przykład, należy rozważyć w tym:

var int a = 5; 
const int b = 7; 
... 
c = process(a*b); 

Kompilator kończy się tworząc instrukcję pomnożyć przez 7, i które przechodzą do „sposobu”, przechowywania wyników w C. Jednak w tym przypadku:

const int a = 5; 
const int b = 7; 
... 
c = process(a*b); 

Kompilator po prostu przekaże 35 do przetworzenia, a nawet nie zakoduje mnożenia. Ponadto, jeśli kompilator wie, że proces nie ma skutków ubocznych (tj. Jest to proste obliczenie), to nawet nie wywoła procesu. To po prostu ustawi c na wartość zwracaną procesu (35), oszczędzając ci wywołanie funkcji.

+0

Świetna odpowiedź, to jest rodzaj rozwiązania, których szukam, na przykład .. – onaclov2000

4

Oznaczenie zmiennej jako stałej deklaruje zamiar programisty, że będzie to stała wartość, ilekroć będzie dostępna podczas wykonywania kodu. Weźmy pod uwagę formę dokumentacji, która również powoduje, że kompilator uwzględnia twój projekt.

0

Stałe są wartościami niezmiennymi, które są znane w czasie kompilacji i nie zmieniają się przez cały czas trwania programu.

Stałe różnią się od zmiennych w jeden znaczący sposób tym, że po przypisaniu wartości do stałej nie można jej później zmienić.

W czasie wykonywania można mieć pewność, że wartość zdefiniowana w stałej nie zmieni się, w związku z czym program nie zostanie złamany.

6

Wiele z tego zależy od tego, jak dobry jest twój optymalizator.

Dobry optymalizator zastąpi referencje stałych literalnymi wartościami podczas kompilacji. Oszczędza to cykle procesora, ponieważ generowany kod maszynowy działa z bezpośrednimi wartościami, zamiast konieczności ładowania wartości z pamięci.

Niektóre optymalizatory rozpoznają, że wartość nie jest modyfikowana po jej zadeklarowaniu, i przekonwertuj ją na stałą dla Ciebie. Nie polegaj na tym zachowaniu.

Ponadto, gdy tylko jest to możliwe, Twój kod powinien egzekwować założenia, które wprowadziłeś podczas programowania. Jeśli "zmienna" nigdy nie powinna zostać zmieniona, deklarowanie jej jako stałej pomoże zapewnić, że ani ty, ani inni deweloperzy, którzy pojawią się później, nie będą świadomie modyfikować "stałej".

3

Jak podkreślasz, możesz nie zyskać żadnej bezpośredniej korzyści ze zmiany niezmiennych zmiennych na stałe stałe. Jednak przy analizie programu przeprowadza się jedną kontrolę, aby sprawdzić punkt deklaracji zmiennej względem punktu odniesienia zmiennej. Tak więc metryki, takie jak zmienne, do których uzyskuje się dostęp przed deklaracją, lub ustawione i resetowane przed odniesieniem itp. Mogą wskazywać na prawdopodobne błędy.

Dzięki jawnemu zadeklarowaniu stałych jako stałych kompilator i narzędzia analityczne wiedzą, że nie ma zamiaru resetować zmiennej w dowolnym momencie.

Dotyczy to również innych programistów pracujących z kodem. Mogą nieumyślnie ustawić zmienną i możesz nie być tego świadom. Deklarowanie stałych pozwoli uniknąć tego typu błędów.

1

Stałe są zwykle przechowywane w pamięci tylko do odczytu, co zapobiega ich zmianie podczas wykonywania, a dostęp do nich może być szybszy lub co najmniej tak szybki, jak dostęp do pamięci RAM.

+0

Przypuszczam, że jest to zależne od systemu, do którego ładowany jest ten konkretny program, nie jestem tego pewien, ale wygląda interesująco, przyjrzę się temu po mojej stronie. – onaclov2000

2

Jedną z korzyści jest to, że jeśli rzeczywiście jest to wartość stała, nie można jej przypadkowo zmienić. Stała powstrzymuje cię od późniejszego wkręcania rzeczy. Jako zmienna, każdy może przyjść i zmienić go później podczas aktualizacji kodu.

Powinno być jasne, które wartości nigdy się nie zmienią i które wartości mogą się zmienić. Constants wzmacniają twoją intencję.


rzeczywistym przykładem świat z młodości:

Nie posiada wbudowany wartości PI w systemie byłem w pracy więc ktoś stworzył zmienną o nazwie PI i gdzieś po drodze, ktoś (ja) zmodyfikowałem tę wartość do 3.14519 (lub coś tam jest) w procedurze, którą napisałem ... a nie w przybliżeniu pi 3.14159). Zostało to ustawione w innym miejscu kodu i od tego momentu wszystkie rodzaje obliczeń były wyłączone. Gdyby ten PI był stały (oczywiście został później zmieniony), nie byłbym w stanie popełnić tego błędu ... przynajmniej nie łatwo.

+0

Całkowicie zgadzam się ze stwierdzeniem, i widzę korzyści w tym zakresie, po prostu myślałem bardziej na temat faktycznego funkcjonowania kodu, kiedy zadałem pytanie. – onaclov2000

19

Jeśli zadeklarujesz coś jako stałą, a następnie przypadkowo spróbujesz zmodyfikować jego wartość w kodzie, kompilator opowie Ci o twoim błędzie. Ta forma sprawdzania typu statycznego jest w rzeczywistości głównym powodem używania stałych.

+0

** Jest to zdecydowanie najważniejszy powód dla stałych! ** Wydajność jest dobra, ale nie większa, a także silnie zależy od kompilatora. Ale gdy części kodu zakładają, że coś ma zawsze tę samą wartość i nagle się zmienia, może przerwać egzekucję! Tak więc decydujesz, co jest ważniejsze, że w ściśle określonych okolicznościach kod działa minimalnie szybciej lub że kod działa poprawnie;) – ntziolis

+0

Myślę, że ta odpowiedź jest daleko od praktyki. Kiedy kodujesz w praktyce, a kompilator mówi, że "const nie może być modyfikowany" w 99% przypadków, wypadek nie był niezamierzoną modyfikacją, ale zapomniałeś zmienić typ;) – abimelex

2

Oprócz tego, co już zostało powiedziane, deklarowanie zmiennej jako stałej daje więcej swobody dla optymalizatora. Może wyeliminować odczyt jego wartości, może wyeliminować potrzebę utworzenia tymczasowej kopii, może wyeliminować samą zmienną (jest to szczególnie prawdziwe w przypadku stałych numerycznych).

Innym dużym przypadkiem użycia dla stałych są stałe obiekty. Mając stały obiekt (lub podając odniesienie do stałego obiektu w funkcji) możesz być pewien, że twój obiekt nie jest modyfikowany, i że mogą być wywoływane tylko metody (zwane metodami const) tego obiektu. Dotyczy to jednak C++, nie jestem pewien, czy ta sama koncepcja jest ważna również w Ada.

2

Inną możliwością, w zależności od języka, jest to, że kompilator może wykonywać pewne optymalizacje w środowisku wielowątkowym, które w innym przypadku byłoby niemożliwe. Tak jakby powiedzieć:

int b=x*f; 
int c=y*f; 

W środowisku wielowątkowym, jeśli f jest zmienna, kompilator może wygenerować przeładowanie F Przed drugiej operacji. Jeśli f jest stałą, a kompilator wie, że wciąż znajduje się w rejestrze, to nie musi przeładowywać.

3

Możliwe, że kompilator może zmniejszyć rozmiar kodu.na przykład w pakiecie System znajdziesz (na komputerze z procesorem x86)

type Bit_Order is (High_Order_First, Low_Order_First); 
Default_Bit_Order : constant Bit_Order := Low_Order_First; 

tak, że dana

case System.Default_Bit_Order is 
    when System.High_Order_First => 
     -- Big-endian processing 
    when System.Low_Order_First => 
     -- Little-endian processing 
end case; 

kompilator może całkowicie wyeliminować „złego” oddział natomiast kod zachowuje swoją mobilność. W przypadku GNAT należy użyć innej niż domyślna optymalizacji, aby to się stało: -O2 Myślę.

Obie gałęzie muszą być kompilowane - jest to optymalizacja, a nie przetwarzanie #ifdef.

2

Z pewnością dla języka takiego jak C i Ada, kompilator wstawi wartość ze stałej bezpośrednio do instrukcji asemblera, co oznacza, że ​​nie będzie konieczna zamiana rejestrów lub odczyt z pamięci ponad to, co jest wymagane do uruchomienia program. Oznacza to dwie rzeczy: główną jest szybkość (prawdopodobnie nie tak wyraźnie w wielu aplikacjach, chyba że są osadzone), a druga to użycie pamięci (zarówno ostatniego rozmiaru binarnego programu, jak i jego śladu pamięci środowiska wykonawczego).

Takie zachowanie sprowadza się do języka i kompilatora, ponieważ język będzie dyktować wszelkie założenia wykonane przez ciebie (programista), a tym samym ograniczenia wydajności języka; i kompilator, ponieważ jego zachowanie może zmienić się od traktowania twojej stałej, jak każdej innej zmiennej, do wstępnego przetworzenia twojego kodu i optymalizacji binarnej prędkości i śladu tak bardzo, jak to tylko możliwe.

Po drugie, jak zostało powiedziane przez itsmatt i jball, umożliwia logiczne uznanie elementu za stały element konfiguracji, a nie za "zmienną"; zwłaszcza w językach programowania wyższego poziomu i językach interpretowanych.

2

To naprawdę nie jest pytanie specyficzne dla Ada.

Ogólne Korzyści płynące stałych nad zmiennych:

  • błędy kod zapobiega „stałe” przypadkowo uzyskiwanie zmodyfikowany.
  • Informuje kompilator, że może przyjąć, że wartość nie zmieni się podczas optymalizacji.

Ada szczególne Korzyści płynące:

  • Dla stałych numerycznych, nie trzeba określić typ (nazwane numery). Jeśli zadeklarujesz to w ten sposób, będzie on użyteczny w dowolnym wyrażeniu dla tego rodzaju liczby. Jeśli zamiast tego używasz zmiennej, można jej używać tylko w wyrażeniach tego typu o konkretnej zmiennej typ.

Przykład:

Seconds_Per_Minute : constant := 60; 
Secs_Per_Min  : Integer := 60; 

type Seconds_Offset is 0 .. Integer'last; --' 

Min1, Secs1 : Integer; 
Min2, Secs2 : Seconds_Offset; 

... 
--// Using the named number, both of these compile no problem. 
Secs1 := Min1 * Seconds_Per_Minute; 
Secs2 := Min2 * Seconds_Per_Minute; 

--// The second line here gives an error, since Integer is a 
--// different type than Seconds_Offset. 
Secs1 := Min1 * Secs_Per_Min; 
Secs2 := Min2 * Secs_Per_Min; 
+0

Errm, ponieważ Positive jest podtypem Integer nie ma tu błędu; i myślę, że chciałeś dzielić, a nie mnożyć! –

+0

@Simon - Wow, dobre połowy. Domyślam się, że moja passa napisanego kodu Ada bez błędu kompilatora pozostaje, jak zawsze, na 0. Przerobiona, aby pokazać, co zamierzałem (mam nadzieję). –

+0

Cóż, wciąż uczę się Ady, ale to bardzo interesujące, że możesz stworzyć stałą zmienną bez typu ... Nie wiedziałem o tym! – onaclov2000

2

Jest jeszcze inna korzyść, stos i rozmiary segmentu danych.

Rozważmy:

function Recurser(i : Integer) return Integer is 
    ia : array(0..9) of Integer 
      := (1, 2, 3, 4, 5, 6, 7, 8, 9, 1000); 
    r : Integer; 
begin 
    if i = 0 then return 0; end if; 
    r := ia(i mod 10); 
    return r + Recurser(i - 1); 
end; 

Za każdym razem, że funkcja recurses utworzyć strukturę 320 bajtów na stosie. Ale ponieważ wartość a nie zmienia się, stos rośnie, aby utrzymać zmienną, która jest stała. Może to być bardzo ważne na platformach wbudowanych z małymi stosami.

Zmienne poziomu pakietu również zwiększają rozmiar segmentu danych. Podnoszenie wymagań dotyczących pamięci.