Proces budowania programu dzieli się na dwa etapy: kompilacja i linkowanie. Pierwszy etap to utworzenie pojedynczych jednostek translacji. Polega to na rekursywnym dołączaniu, przez preprocesor tekstu, do każdego pliku cpp, odpowiednich plików nagłówkowych (#include). Po wykonaniu tych operacji, następuje kompilacja i zostaje utworzony plik *.obj o takiej samej nazwie. Gdy powstaną wszystkie jednostki translacji, linkier (konsolidator) łączy w całość powstałe pliki obj, dając nam wynikowy program (etap drugi).
Nie zawsze jednak jest tak różowo. Kompilacja jak i linkowanie mogą zakończyć się błędami. Błędy kompilacji są zazwyczaj dość proste do naprawienia - IDE pokazuje nam miejsce wystąpienia oraz przyczynę. Gorzej jest z błędami podczas linkowania, jednak i te po krótkim czasie stają się oczywiste. Najczęściej spotykanym problemem, jest użycie niezaimplementowanej funkcji lub metody (unresolved external symbol). Czasem w pośpiechu, zapomnimy o samej main() (unresolved external symbol _main), lub utworzymy zły typ projektu i zamiast WinMain napiszemy znane z konsloli main() (unresolved external symbol _WinMain@16). Czasem możemy natrafić jednak na problemy zwiazane z powonym zadeklarowaniem, lub zdefiniowaniem obiektów, zmiennych. Jak się przed tym ustrzec? Poznać kilka prostych zasad ;)
Nazwa jest konsolidowana (łączona) wewnętrznie, jeśli jest nazwą lokalną wewnątrz jej jednostki translacyjnej i podczas linkowania nie koliduje z identyczną nazwą, zdefiniowaną w innej jednosce translacyjnej.
No tak. Oczywiste prawda? Prawda ;) Po krótce, jeśli zdefiniujemy jakąś zmienną łączoną wewnętrznie w pliku cpp w globalnej przestrzeni nazw, zmienna ta będzie widoczna tylko w tym pliku i nie wywoła kolizji podczas linkowania z innym plikiem, w którym jest zdefiniowana inna zmienna o tej samej nazwie. Łączenie zewnętrzne działa w odwrotny sposób - dana definicja nie może zostać powtórzona w innych jednostkach translacji, bo wywoła kolizje podczas linkowania.
Jakie typy są w jaki sposób łączone?
Linkowne zewnętrzne są:
- definicje zmienych
- definicje funkcji i metod niebedących inline
- statyczne składowe klas
- deklaracje z modyfikatorem extern
Łączone wewnętrznie są:
- deklaracje i definicje klas
- definicje typów za pomocą typedef
- metody klas typu inline
- globalne definicje statyczne
- typy wyliczeniowe
- stałe
Pewnie nie są to wszystkie możliwości, jednak te najważniejsze. Wiedza ta czasem okaże się przydatna, w szczególności gdy korzystamy z zewnętrznych bibliotek, pisanych bez użycia przestrzeni nazw i "podstawowych zasad bezpieczeństwa" ;) .
No, całkiem ładnie napisane ;) tylko dwa razy musiałem przeczytać zanim zrozumiałem :D. (aczkolwiek pierwszy raz czytałem jakoś o 2 w nocy :P)
OdpowiedzUsuńPod Twoim tajemniczym "globalne definicje statyczne" kryje się konstrukcja:
OdpowiedzUsuństatic int ZmiennaGlobalna;
która służy właśnie do definiowania zmiennych jako linkowane wewnętrznie, bo domyślnie są zewnętrznie. I tutaj słowo static działa zupełnie inaczej niż statyczne pola i metody klas albo statyczne zmienne lokalne wewnątrz funkcji/metod. Można to było jaśniej podkreślić :)
Sądziłem, że jest to w miarę oczywiste ;)
OdpowiedzUsuńjak ktoś wie co to jest,to faktycznie jest oczywiste :P. A jak się nie wie, to nie jest oczywiste :P (powiedział filozoficznie thaven i oddał mocz za firankę :P)
OdpowiedzUsuń