C/Więcej o kompilowaniu: Różnice pomiędzy wersjami

Przejdź do nawigacji Przejdź do wyszukiwania
Użyto szablon {{Uwaga}}, pokolorowano kod
(Użyto szablon {{Uwaga}}, pokolorowano kod)
 
=== Budowa pliku Makefile ===
{{Uwaga: poniżej|Poniżej został omówiony Makefile dla GNU Make. Istnieją inne programy make i mogą używać innej składni. Na Wikibooks został też obszernie opisany [[Borland C++ Compiler/MAKE|program make firmy Borland]].}}
 
 
Często zdarza się, że kompilator w ramach optymalizacji "wyrównuje" elementy struktury tak, aby procesor mógł łatwiej odczytać i przetworzyć dane. Przyjrzyjmy się bliżej następującemu fragmentowi kodu:
 
<source lang="c">
typedef struct {
unsigned char wiek; /* 8 bitów */
unsigned char plec; /* 8 bitów */
} nasza_str;
</source>
 
Aby procesor mógł łatwiej przetworzyć dane kompilator może dodać do tej struktury jedno, ośmiobitowe pole. Wtedy struktura będzie wyglądała tak:
 
<source lang="c">
typedef struct {
unsigned char wiek; /*8 bitów */
unsigned char plec; /* 8 bitów */
} nasza_str;
</source>
 
Wtedy rozmiar zmiennych przechowujących wiek, płeć, oraz dochód będzie wynosił 64 bity - będzie zatem potęgą liczby dwa i procesorowi dużo łatwiej będzie tak ułożoną strukturę przechowywać w pamięci cache. Jednak taka sytuacja nie zawsze jest pożądana. Może się okazać, że nasza struktura musi odzwierciedlać np. pojedynczy pakiet danych, przesyłanych przez sieć. Nie może być w niej zatem żadnych innych pól, poza tymi, które są istotne do transmisji. Aby wymusić na kompilatorze wyrównanie 1-bajtowe (co w praktyce wyłącza je) należy przed definicją struktury dodać dwie linijki. Ten kod działa pod Visual C++:
 
<source lang="c">
#pragma pack(push)
#pragma pack(1)
#pragma pack(pop)
</source>
 
W kompilatorze GCC mamy jeszcze jedną możliwość,należy po deklaracji struktury dodajemy przed średnikiem kończącym jedną linijkę:
 
__attribute__ ((packed))
Dzięki użyciu tego atrybutu, kompilator zostanie "zmuszony" do braku ingerencji w naszą strukturę. Jest jednak jeszcze jeden, być może bardziej elegancki sposób na obejście dopełniania. Zauważyłeś, że dopełnienie, dodane przez kompilator pojawiło się między polem o długości 8 bitów (plec) oraz polem o długości 32 bitów (dochod). Wyrównywanie polega na tym, że dana zmienna powinna być umieszczona pod adresem będącym wielokrotnością jej rozmiaru. Oznacza to, że jeśli np. mamy w strukturze na początku dwie zmienne, o rozmiarze jednego bajta, a potem jedną zmienną, o rozmiarze 4 bajtów, to pomiędzy polami o rozmiarze 2 bajtów, a polem czterobajtowym pojawi się dwubajtowe dopełnienie. Może Ci się wydawać, że jest to tylko niepotrzebne mącenie w głowie, jednak niektóre architektury (zwłaszcza typu [[w:RISC|RISC]]) mogą nie wykonać kodu, który nie został wyrównany. Dlatego, naszą strukturę powinniśmy zapisać mniej więcej tak:
<source lang="c">
typedef struct {
unsigned short dochod; /* 16 bitów */
unsigned char plec; /* 8 bitów */
} nasza_str;
</source>
 
W ten sposób wyrównana struktura nie będzie podlegała modyfikacjom przez kompilator oraz będzie przenośna pomiędzy różnymi kompilatorami.
9

edycji

Menu nawigacyjne