C/Przenośność programów: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Pokolorowano kod
Linia 25:
Jednak możemy posiadać implementację, która nie posiada tego pliku nagłówkowego. W takiej sytuacji nie pozostaje nam nic innego jak tworzyć własny plik nagłówkowy, w którym za pomocą słówka '''typedef''' sami zdefiniujemy potrzebne nam typy. Np.:
 
<source lang="c">
typedef unsigned char u8;
typedef signed char s8;
Linia 33 ⟶ 34:
typedef unsigned long long u64;
typedef signed long long s64;
</source>
 
Aczkolwiek należy pamiętać, że taki plik będzie trzeba pisać od nowa dla każdej architektury na jakiej chcemy kompilować nasz program.
Linia 54 ⟶ 56:
 
Przykładem może być komunikacja sieciowa, w której przyjęło się, że dane przesyłane są w porządku big-endian. Aby móc łatwo operować na takich danych, w standardzie POSIX zdefiniowano następujące funkcje (w zasadzie zazwyczaj są to makra):
<source lang="c">
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
Linia 59 ⟶ 62:
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
</source>
 
Pierwsze dwie konwertują liczbę z reprezentacji lokalnej na reprezentację big-endian (''host to network''), natomiast kolejne dwie dokonują konwersji w drugą stronę (''network to host'').
Linia 64 ⟶ 68:
Można również skorzystać z pliku nagłówkowego endian.h, w którym definiowane są makra pozwalające określić porządek bajtów:
 
<source lang="c">
#include <endian.h>
#include <stdio.h>
Linia 79 ⟶ 84:
return 0;
}
</source>
 
Na podstawie makra __BYTE_ORDER można skonstruować funkcję, która będzie konwertować liczby pomiędzy porządkiem różnymi porządkami:
 
<source lang="c">
#include <endian.h>
#include <stdio.h>
Linia 119 ⟶ 126:
return 0;
}
</source>
 
Ciągle jednak polegamy na niestandardowym pliku nagłówkowym endian.h. Można go wyeliminować sprawdzając porządek bajtów w czasie wykonywania programu:
 
<source lang="c">
#include <stdio.h>
#include <stdint.h>
Linia 140 ⟶ 149:
}
return 0;
}
</source>
 
Powyższe przykłady opisują jedynie część problemów jakie mogą wynikać z próby przenoszenia binarnych danych pomiędzy wieloma platformami. Wszystkie co więcej zakładają, że bajt ma 8 bitów, co wcale nie musi być prawdą dla konkretnej architektury, na którą piszemy aplikację. Co więcej liczby mogą posiadać w swojej reprezentacje bity wypełnienia (ang. ''padding bits''), które nie biorą udziały w przechowywaniu wartości liczby. Te wszystkie różnice mogą dodatkowo skomplikować kod. Toteż należy być świadomym, iż przenosząc dane binarnie musimy uważać na różne reprezentacje liczb.
Linia 165 ⟶ 175:
Przy zwiększaniu przenośności kodu może pomóc preprocessor. Przyjmijmy np., że chcemy korzystać ze słówka kluczowego inline wprowadzonego w standardzie C99, ale równocześnie chcemy, aby nasz program był rozumiany przez kompilatory ANSI C. Wówczas, możemy skorzystać z następującego kodu:
 
<source lang="c">
#ifndef __inline__
# if __STDC_VERSION__ >= 199901L
Linia 172 ⟶ 183:
# endif
#endif
</source>
 
a w kodzie programu zamiast słówka inline stosować __inline__. Co więcej, kompilator GCC rozumie słówka kluczowe tak tworzone i w jego przypadku warto nie redefiniować ich wartości:
 
<source lang="c">
#ifndef __GNUC__
# ifndef __inline__
Linia 184 ⟶ 197:
# endif
#endif
</source>
 
Korzystając z kompilacji warunkowej można także korzystać z różnego kodu zależnie od (np.) systemu operacyjnego. Przykładowo, przed kompilacją na konkretnej platformie tworzymy odpowiedni plik config.h, który następnie dołączamy do wszystkich plików źródłowych, w których podejmujemy decyzje na podstawie zdefiniowanych makr. Dla przykładu, plik config.h:
 
<source lang="c">
#ifndef CONFIG_H
#define CONFIG_H
Linia 200 ⟶ 215:
#endif
</source>
 
Jakiś plik źródłowy:
 
<source lang="c">
#include "config.h"
Linia 212 ⟶ 229:
rob_cos_wersja_dla_linux();
#endif
</source>
 
Istnieją różne narzędzia, które pozwalają na automatyczne tworzenie takich plików config.h, dzięki czemu użytkownik przed skompilowaniem programu nie musi się trudzić i edytować ich ręcznie, a jedynie uruchomić odpowiednie polecenie. Przykładem jest zestaw autoconf i automake.