Posts tagged ‘constants’

Skąd wziąć matematyczne stałe

2009-05-09 12:24

Jeśli tylko liczymy coś bardziej skomplikowanego niż rozmieszczenie kontrolek w oknie, to niechybnie zaczniemy potrzebować którejś ze stałych matematycznych – na przykład π. Co wtedy robimy? Ano całkiem często skutkuje to włączeniem do programu deklaracji typu:

  1. const double PI = 3.14159265358979;

Nie jest to oczywiście wielkie zło (a już na pewno mniejsze niż bezpośrednie korzystanie z definicji typu π = 4atan(1)), ale w większości przypadków jest to też wyważanie otwartych drzwi. Potrzebne stałe mamy bowiem często już gdzieś zdefiniowane – trzeba tylko wiedzieć, gdzie ich poszukać:

  • W C/C++ mamy M_PI, M_E, a nawet M_LN10 czy M_SQRT2 zdefiniowane w math.h lub cmath. Definicje te nie są jednak częścią standardu, więc dbające o zgodność kompilatory (czyli większość kompilatorów w ogóle) wymagają pewnych #define‘ów przed dołączeniem ww. nagłówków. I tak dla Visual C++ jest to _USE_MATH_DEFINES, a dla GCC bodajże prawie dowolne z makr _SOURCE (jak _GNU_SOURCE czy _ALL_SOURCE).
  • W DirectX mamy tylko DX3DX_PI i D3DX1BYPI (1/π) – co nie dziwi, bo przecież w grafice więcej do szczęścia nie potrzeba ;) Obie te stałe są zdefiniowane w d3dx#math.h (gdzie # to numer wersji DirectX), który to nagłówek jest dołączany automatycznie jeśli korzystamy z D3DX.
  • W .NET mamy stałe PI i E zdefiniowane jako statyczne pola klasy System.Math. W Javie klasa java.lang.Math zawiera dwa identycznie zdefiniowane pola.

Jak zatem łatwo zauważyć, wynajdywanie koła w postaci definicji π czy e jest w wielu przypadkach nieuzasadnione :]

Tags: ,
Author: Xion, posted under Math, Programming » 13 comments

Stałe i zmienne pola statyczne

2008-02-27 1:06

Modyfikator static ma w C++ kilka różnych funkcji, a jedną z nich jest deklarowanie składników statycznych w klasach. Jak doskonale wiadomo taki składnik jest wspólny dla wszystkich obiektów tejże klasy i można go używać nawet, jeśli takie obiekty w ogóle nie istnieją.
Zwykle nie ma większych problemów ze statycznymi metodami, natomiast w przypadku pól sprawa często potrafi się skomplikować. Zwłaszcza, że statyczne elementy zmienne i stałe deklarujemy nieco inaczej…

Przede wszystkim należy pamiętać, że statyczne zmienne są właściwie pewnym rodzajem zmiennych globalnych, różniącym się prawie wyłącznie pod względem składniowym. A w przypadku zmiennych globalnych (deklarowanych w nagłówkach poprzez extern) konieczne jest ich przypisanie do jakiegoś modułu kodu, czyli pliku .cpp. Dzięki temu linker może potem powiązać odwołania do tej zmiennej z nią samą niezależnie od miejsca jej użycia.
To samo dotyczy statycznych pól:

  1. // foo.hpp
  2. class Foo   { private:   static int ms_iBar; };
  3.  
  4. // foo.cpp
  5. int Foo::ms_iBar = 0;

Jest jednak drobna różnica między statycznymi stałymi a zmiennymi polami. W tym drugim przypadku możemy zmiennej nadać początkową wartość; robimy to już w pliku .cpp przy jej definicji – tak jak powyżej. Zrobienie tego od razu w deklaracji jest niedopuszczalne.
Natomiast dla stałych wartość podać musimy i zwykle czynimy to dla odmiany właśnie w pliku nagłówkowym, jeszcze wewnątrz bloku class:

  1. // foo.hpp
  2. class Foo   { public:   static const int BAR = 10; };
  3.  
  4. // foo.cpp
  5. const int Foo::BAR;

Wówczas z kolei nie możemy wręcz inicjalizować stałej ponownie w pliku .cpp!

Dość dziwne, prawda? Ale w miarę łatwo to wyjaśnić. Otóż stała ma, jak sama nazwa wskazuje stałą wartość. Dzięki temu, że jest podana w nagłówku, kompilator może zoptymalizować każde miejsce jej normalnego użycia. Zamiast odwoływania się do pamięci, wpisze po prostu wartość stałej “na sztywno” w kodzie wynikowym. Będzie więc to podobne do działania #define.
Tym niemniej jest to pewna niedogodność, jeśli statyczne stałe i statyczne zmienne definiuje się inaczej. Ale przecież to nie jedyna dziwna cecha C++, która sprawia, że tak ten język lubimy ;-)

Tags: , , ,
Author: Xion, posted under Programming » 7 comments

Liczenie stałych

2007-08-07 11:59

Dzisiaj pokażę pewną sztuczkę, mogącą nieco ułatwić życie programiście, który – jak wiadomo – zawsze ma za dużo pracy. Nie jest ona zbyt odkrywcza ani pomysłowa, ale ponieważ wielokrotnie zdarzyło mi się z niej korzystać (ostatni raz całkiem niedawno), sądzę że zasługuje na wzmiankę.

Sprawa dotyczy typów wyliczeniowych w C++ – czyli tworów, które pojawiają się często w większości programów. W moim ostatnim przypadku był to prosty typ definiujący wachlarz kolorów używanych w różnych miejscach systemu GUI:

  1. enum GUI_COLOR
  2. {
  3.     // kolory pasków tytułu okien
  4.     GC_ACTIVE_CAPTION, GC_INACTIVE_CAPTION,
  5.     // kolory kontrolek
  6.     GC_CONTROL_NORMAL, GC_CONTROL_HOVER,
  7.     // kolor tła okna
  8.     GC_WINDOW
  9. };

Jest to podobny zestaw do tego, jaki można zobaczyć w Windows w oknie Właściwości: Ekran, na zakładce Wygląd. Naturalnie jest on dość okrojony, jako że nie potrzebujemy tutaj niczego aż tak skomplikowanego. Nie jest jednak wykluczone, że kiedyś się rozrośnie…
Każdemu z tych “systemowych” kolorów trzeba teraz przyporządkować kolor rzeczywisty – żeby wiedzieć, jak narysować konkretne kontrolki. Można zdefiniować do tego sporo zmiennych w stylu clActiveCaptionColor czy clControlNormalColor, ale lepszym rozwiązaniem jest tablica:

  1. COLOR aColors[???];

Problem w tym, że trzeba podać jej rozmiar. Można oczywiście wpisać tam na sztywno 5, ale doskonale wiadomo, jakie są skutki stosowania w kodzie “magicznych liczb”. Można zdefiniować sobie stałą, lecz wtedy też będziemy musieli ręcznie modyfikować jej wartość, jeżeli liczba kolorów się zmieni.

Potrzebujemy więc sposobu na automatyczne określenie liczby stałych zdefiniowanych w typie wyliczeniowym. W językach dysponujących dynamicznymi informacjami o typie – jak C# czy Java – byłoby to zapewne proste, lecz tutaj nie mamy tego komfortu. Zamiast tego możemy sobie jednak poradzić inaczej – dodając do typu wyliczeniowego kolejną stałą:

  1. enum GUI_COLOR
  2. {
  3.    /* ... */
  4.  
  5.    // na końcu
  6.    GC_COUNT
  7. };

Kompilator nada jej wartość o jeden większą od poprzedniej. Ponieważ pierwszej stałej przypisał zero, GC_COUNT będzie odpowiadało liczbie 5 i to będzie właśnie liczba użytecznych stałych w typie wyliczeniowym. Teraz można już zadeklarować potrzebną tablicę:

  1. COLOR aColors[GC_COUNT];

Podobnie można zrobić dla każdego typu wyliczeniowego. Najlepiej działa to wtedy, gdy kompilator sam numeruje jego stałe. Jeżeli sami to robimy, to oczywiście trik nadal będzie działał (zmienna *_COUNT będzie zawsze miała największa wartość). W tablicy pojawią się jednak niewykorzystane elementy i te dziury ewentualnie trzeba będzie omijać.

Tags: , ,
Author: Xion, posted under Programming » Comments Off on Liczenie stałych
 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.