[ Pobierz całość w formacie PDF ]

struct domain {
int dom_family; /* AF_xxx */
char *dom_name;
33
netbsdsrc/sys/netinet/tcp.h: 43  47.
34
netbsdsrc/sys/msdosfs/bpb.h: 22  34.
35
netbsdsrc/sys/sys/domain.h: 50  65.
88 Czytanie kodu. Punkt widzenia twórców oprogramowania open-source
void (*dom_init)(void); /* initialize domain data structures */
[...]
int (*dom_rtattach)(void **, int);
/* initialize routing table */
int dom_rtoffset; /* an arg to rtattach, in bits */
int dom_maxrtkey; /* for routing layer */
};
Po wprowadzeniu takiej deklaracji, zmienne określonego typu strukturalnego, czy też
ściślej rzecz ujmując  wskazniki na typ strukturalny  po odpowiednim zainicjali-
zowaniu mogą być traktowane w sposób przypominający użycie obiektów w językach
C++ i Java36.
for (dom = domains; dom; dom = dom->dom_next)
if (dom->dom_family == i && dom->dom_rtattach) {
dom->dom_rtattach((void **)&nep->ne_rtable[i],
dom->dom_rtoffset);
break;
Ze względu na fakt, że  obiekty mogą być inicjalizowane za pomocą różnych  metod
(wskazników na funkcje), a jednak są używane poprzez ten sam interfejs (wywołania
następują poprzez te same nazwy składowych struktur), opisana technika stanowi im-
plementację metod wirtualnych (ang. virtual methods), dostępnych w językach obiekto-
wych, oraz programowania polimorficznego (ang. polymorphic programming). W rze-
czywistości, ze względu na fakt, że obiekty należące do tej samej klasy współużytkują
swoje metody (ale nie pola), wskazniki na metody są często dzielone przez różne obiekty
dzięki przechowywaniu w strukturze  obiektów jedynie wskaznika na inną strukturę
zawierającą wskazniki na faktyczne metody37.
struct file {
[...]
short f_type; /* descriptor type */
short f_count; /* reference count */
short f_msgcount; /* references from message queue */
struct ucred *f_cred; /* credentials associated with descriptor */
struct fileops {
int (*fo_read)(struct file *fp, struct uio *uio,
struct ucred *cred);
int (*fo_write)(struct file *fp, struct uio *uio,
struct ucred *cred);
int (*fo_ioctl)(struct file *fp, u_long com,
caddr_t data, struct proc *p);
int (*fo_poll)(struct file *fp, int events,
struct proc *p);
int (*fo_close)(struct file *fp, struct proc *p);
} *f_ops;
off_t f_offset;
caddr_t f_data; /* vnode or socket */
};
W powyższym przykładzie każdy obiekt reprezentujący otwarty plik lub gniazdo dzieli
swoje metody read, write, ioctl, poll oraz close poprzez składową struktury f_ops,
wskazującą na dzieloną strukturę fileops.
36
netbsdsrc/sys/kern/vfs_subr.c: 1436  1440.
37
netbsdsrc/sys/sys/file.h: 51  73.
Rozdział 3. f& Zaawansowane typy danych języka C 89
wiczenie 3.6. Alternatywnym sposobem przekazywania do funkcji danych typu tabli-
cowego przez wartość i zwracania ich jako rzeczywistych wartości jest zawarcie tablicy
w strukturze. Zlokalizuj takie przykłady na płycie dołączonej do książki. Wyjaśnij,
dlaczego takie podejście nie jest wykorzystywane zbyt często.
wiczenie 3.7. Zlokalizuj 20 oddzielnych wystąpień struktur na płycie dołączonej do
książki i określ powód ich wykorzystania. Zapoznaj się z biblioteką struktur danych
ogólnego przeznaczenia, taką jak STL języka C++ lub java.util. Wskaż, które wystą-
pienia można by zapisać korzystając z biblioteki. Zminimalizuj czas poświęcony każ-
demu wystąpieniu.
wiczenie 3.8. Wiele technik, bibliotek oraz narzędzi obsługuje przenośne kodowanie
danych w celu ich przenoszenia między aplikacjami. Określ techniki mające zastoso-
wanie w Twoim środowisku i porównaj je z użyciem podejścia bazującego na struktu-
rach języka C.
3.3. Unie
Konstrukcja języka C union grupuje elementy, które dzielą ten sam obszar pamięci.
Możliwy jest dostęp tylko do jednego elementu naraz spośród współużytkujących taki
obszar. Unie są używane w języku C w celu:
zapewnienia wydajnego wykorzystania pamięci;
zaimplementowania polimorfizmu;
umożliwienia dostępu do danych przy użyciu różnych reprezentacji wewnętrznych.
3.3.1. Wydajne wykorzystanie pamięci
Często spotykane uzasadnienie wykorzystania unii dotyczy współużytkowania tego
samego obszaru pamięci w dwóch różnych celach. Ma to na celu zaoszczędzenie przy-
najmniej kilku bajtów pamięci. Istnieją przypadki, w których unie są wykorzystywane
wyłącznie w tym celu. Jednak w przypadku, gdy urządzenia wbudowane obsługują
pamięć o wielomegabajtowej pojemności, używanie unii staje się nieuzasadnione.
Oprócz starszego kodu można również spotkać przypadki, gdy duża liczba obiektów
opartych na unii uzasadnia dodatkowe wysiłki związane z napisaniem odpowiedniego
kodu. Poniższy przykład pochodzący z funkcji malloc standardowej biblioteki języka
C to typowy przypadek38.
union overhead {
union overhead *ov_next; /* when free */
struct {
u_char ovu_magic; /* magic number */
u_char ovu_index; /* bucket # */
#ifdef RCHECK
u_short ovu_rmagic; /* range magic number */
38
netbsdsrc/lib/libc/stdlib/malloc.h: 78  92.
90 Czytanie kodu. Punkt widzenia twórców oprogramowania open-source
u_long ovu_size; /* actual block size */
#endif
} ovu;
#define ov_magic ovu.ovu_magic
#define ov_index ovu.ovu_index
#define ov_rmagic ovu.ovu_rmagic
#define ov_size ovu.ovu_size
}; [ Pobierz całość w formacie PDF ]

  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • projektlr.keep.pl