2009-08-04 20 views
18

Używam statycznej inicjalizacji, aby ułatwić proces rejestracji niektórych klas z fabryki w C++. Niestety, myślę, że kompilator optymalizuje "nieużywane" obiekty, które mają za zadanie wykonywać użyteczną pracę w swoich konstruktorach. Czy istnieje sposób, aby powiedzieć kompilatorowi, aby nie optymalizować zmiennej globalnej?W jaki sposób mogę zapobiec kompilacji moich "nieużywanych" zmiennych globalnych?

class SomeClass { 
    public: 
     SomeClass() { 
      /* do something useful */ 
     } 
}; 

SomeClass instance; 

Mój punkt przerwania w konstruktorze SomeClass nie zostaje trafiony. W moim rzeczywistym kodzie SomeClass znajduje się w pliku nagłówkowym, a instancja jest w pliku źródłowym, mniej lub bardziej samodzielnie.

EDYCJA: Jak można się domyślić, KJAWolf, kod ten jest faktycznie skompilowany do statycznej biblioteki, a nie do pliku wykonywalnego. Jego celem jest zarejestrowanie niektórych typów dostarczanych przez statyczną bibliotekę statyczną listę typów i ich twórców, dla fabryki, która następnie będzie czytać z konstrukcji. Ponieważ te typy są dostarczane z biblioteką, dodanie tego kodu do pliku wykonywalnego jest niepożądane.

Odkryłem również, że przenoszenie kodu do innego pliku źródłowego zawierającego inny istniejący kod działa poprawnie. Wygląda na to, że przyczyną problemu jest posiadanie pliku składającego się wyłącznie z tych globalnych obiektów. To tak, jakby ta jednostka tłumaczeniowa została całkowicie zignorowana.

+1

Czy plik źródłowy jest częścią pliku wykonywalnego, czy jest częścią biblioteki statycznej? – KJAWolf

+0

Aha, dobra robota divining. W rzeczywistości plik źródłowy jest częścią statycznej biblioteki lib. Czy to spowoduje problem? Jestem 80% pewny, że zrobiłem dokładnie to samo wcześniej i to zadziałało. –

+0

miałem ten sam problem: http://stackoverflow.com/questions/599035/force-visual-studio-to-link-all-symbols-in-a-lib-file – Lodle

Odpowiedz

34

Kompilator nie może optymalizować obiektów globalnych.
Nawet jeśli nigdy nie są używane.

Coś jeszcze dzieje się w kodzie.
Teraz, jeśli zbudowałeś statyczną bibliotekę z twoim globalnym obiektem, a ten globalny obiekt nie jest przywoływany z pliku wykonywalnego, nie zostanie on wciągnięty do pliku wykonywalnego przez linker.

+9

Ulepszyłem to, ponieważ uważam, że jest to jedyna odpowiedź, która nabija prawdziwy problem; Jak pyta: "Wydaje się, że przyczyną problemu jest posiadanie pliku składającego się wyłącznie z tych globalnych obiektów, tak jakby ta jednostka tłumaczeniowa została całkowicie zignorowana". Jednostka tłumaczeniowa jest ignorowana w tym sensie, że jest pomijana przez linker, ponieważ znajduje się w bibliotece. Jeśli obiekt znajduje się w bibliotece i nie jest wywoływany przez nic w aplikacji, jest pomijany, to cała idea biblioteki! –

+0

Ditto, które uderzyło w gwóźdź w głowę. Przegłosowałem również odpowiedź Pavela, ponieważ on też to zrobił dobrze :) –

+1

Jak to naprawić? – Sam

5

Kompilator nigdy nie powinien optymalizować takich globali - jeśli to robi, jest po prostu zepsuty.

+3

Jeśli kompilator nie wykryje użycia globalnego, może je pominąć. GCC (G ++ w tym kontekście) może i pomija niektóre zmienne - na przykład stara "osadzić wersję w pliku obiektowym" sztuczki nie działają z nowoczesnym GCC - wartość statyczna pliku jest wykrywana jako nieużywana i zoptymalizowana poza obiektem plik. –

+0

plik statyczny! = Globalny –

+0

Jeśli mają one cnstructor, to istnieje potencjalny wpływ strony z wykorzystaniem konstruktora. Ponieważ gcc nie analizuje funkcji krzyżowej, nigdy nie byłby w stanie wykryć potencjalnego wpływu strony, a zatem nie mógłby go usunąć. –

2

Aby zbudować Arthura Ulfeldta, volatile mówi kompilatorowi, że zmienna ta może się zmienić poza wiedzą o kompilatorze. Użyłem go do wstawienia instrukcji zezwalającej debuggerowi na ustawienie punktu przerwania. Jest także przydatny w rejestrach sprzętowych, które mogą zmieniać się w zależności od środowiska lub wymagać specjalnej sekwencji. tzn. rejestr odbioru portu szeregowego i pewne rejestry watchdoga.

+1

Nie, po prostu mówi kompilator, że nie może buforować poprzednio odczytanej wartości zmiennej. –

+0

Przydaje się do wielowątkowość :) – Partial

+2

lotny nie działa dla wielowątkowości :( – paulm

1

można użyć

 
#pragma optimize off 
int globalVar 
#pragma optimize on 

ale nie wiem jeśli to działa tylko w Visual Studio (http://msdn.microsoft.com/en-us/library/chh3fb0k(VS.80).aspx).

Można również powiedzieć, że kompilator nie optymalizacji w ogóle, zwłaszcza jeśli debugowanie ...

+0

To nie jest kompatybilne z każdym IDE/kompilatorami. – Partial

+0

, ale chciałbym, żeby to było! – radsdau

+0

W Visual Studio składnia jest #pragma optimize ("", off) ale dla mnie nie uniemożliwia to usunięcia zmiennej globalnej w bibliotece statycznej. – gast128

0

Czy używasz gcc z gdb? W przeszłości wystąpił problem, w którym gdb nie mógł dokładnie ustawić punktów przerwania w konstruktorze.

Czy używasz również poziomu optymalizacji, który umożliwia kompilatorowi inline metody w definicji klasy.

-2

Co powiesz na użycie słowa kluczowego volatile? Zapobiegnie to zbyt dużej optymalizacji kompilatora.

0

Mam taki sam problem z instalacją na VS2008. Znalazłem, że jeśli zadeklarujesz klasę z dllexport, nie zostanie ona zoptymalizowana.

class __declspec(dllexport) Cxxx 
{ 
. 
} 

Jednak generuje to wiele ostrzeżeń w moim przypadku, ponieważ muszę zadeklarować wszystkie klasy używane w tej klasie także jako dllexport.

Wszystkie optymalizacje są wyłączone (w trybie debugowania), nadal jest to zoptymalizowane. Również zmienna/pragma optymalizuje się. Na zmiennej globalnej utworzonej z tej klasy (w tym samym pliku cpp) itp. Nie działa.

Po prostu okazało się, że dllexport wymaga co najmniej włączenia plików nagłówkowych tych klas w innym pliku cpp od exe do pracy! Tak więc jedyną opcją jest dodanie pliku z wywołaniami do statycznych członków dla każdej klasy i dodanie tego pliku do wszystkich projektów, w których używane są te klasy.

1

Można wymusić, że jeden obiekt (Lista rodzajów) ciągnie kilka innych obiektów z nią częściowo łączenie je przed zbudowaniem kompletny statyczny lib.

Z GNU linker:

ld -Ur -o TypeBundle.o type1.o type2.o type3.o static_list.o 
ld -static -o MyStaticLib.a type_bundle.o other_object.o another_object.o ... 

Tak więc, gdy lista statyczna odwołuje kodu przy użyciu biblioteki, pełna „TypeBundle.o” obiekt dostanie połączony do otrzymanego binarnego, w tym type1.o, type2 .o i type3.o.

W tym miejscu sprawdź znaczenie "-Ur" w the manual.

Powiązane problemy