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

brak opisu edycji
m (→‎Program make: include)
Nie podano opisu zmian
 
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:
 
<sourcesyntaxhighlight lang="c">
typedef struct {
unsigned char wiek; /* 8 bitów */
unsigned char wzrost; /* 8 bitów */
} nasza_str;
</syntaxhighlight>
</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:
 
<sourcesyntaxhighlight lang="c">
typedef struct {
unsigned char wiek; /*8 bitów */
unsigned char wzrost; /* 8 bitów */
} nasza_str;
</syntaxhighlight>
</source>
 
Wtedy rozmiar zmiennych przechowujących wiek, wzrost, 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++:
 
<sourcesyntaxhighlight lang="c">
#pragma pack(push)
#pragma pack(1)
#pragma pack(pop)
</syntaxhighlight>
</source>
 
W kompilatorze GCC, należy dodać po deklaracji struktury przed średnikiem kończącym jedną linijkę:
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 (wiek) 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:
<sourcesyntaxhighlight lang="c">
typedef struct {
unsigned int dochod; /* 32 bity */
unsigned char plec; /* 8 bitów */
} nasza_str;
</syntaxhighlight>
</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.