13.9.08

Penataan Posisi Data

(bagian 5 dari 7 artikel - ke artikel utama)

Kompailer gcc menata setiap field (ruas) dari struktur data ke lokasi memori yang dianggapnya akan mempercepat eksekusi program. Sebagai contoh perhatikan program berikut beserta outputnya:
#include <stdio.h>
#include <stddef.h>

struct foo {
char a;
short b;
int c;
};

#define OFFSET_A offsetof(struct foo, a)
#define OFFSET_B offsetof(struct foo, b)
#define OFFSET_C offsetof(struct foo, c)

int main()
{
printf ("offset A = %d\n",OFFSET_A);
printf ("offset B = %d\n",OFFSET_B);
printf ("offset C = %d\n",OFFSET_C);
return 0;
}
Output program ini adalah:
offset A = 0
offset B = 2
offset C = 4
Output program menunjukkan bahwa kompailer menata ruas variabel b dan c pada struktur foo pada alamat memori genap. Ini tidak baik JIKA kita ingin menuliskan satu per satu data pada struktur itu ke SATU alamat memori. Biasanya struktur data sebuah driver mempunyai lokasi byte berurutan. Oleh karena itu atribut gcc ((packed)) digunakan untuk meminta kompailer agar tidak membuat "lubang memori" dalam struktur data. (Perhatikan bahwa A berukuran satu byte, tapi B terletak di offset ke-2 sehingga offset ke-1 kosong dan tidak digunakan).

Jika struktur foo diubah menggunakan atribut packed:
struct foo {
char a;
short b;
int c;
} __attribute__((packed));
Maka output program akan menjadi sebagai berikut:
offset A = 0
offset B = 1
offset C = 3
Sekarang tidak ada lagi lubang memori di dalam struktur (offset ke-1 ditempati variabel b).

Atribut packed dapat digunakan terhadap seluruh struktur, seperti contoh di atas, atau digunakan terhadap ruas tertentu.

Sebagai contoh, struktur usb_ctrlrequest pada include/usb.h didefinisikan sebagai berikut:
struct usb_ctrlrequest {
__u8 bRequestType;
__u8 bRequest;
__le16 wValue;
__le16 wIndex;
__le16 wLength;
} __attribute__ ((packed));
untuk memastikan seluruh struktur tidak mempunyai lubang memori, sehingga datanya dapat langsung ditulis ke port USB.

Namun struktur usb_endpoint_descriptor didefinisikan seperti berikut ini:
struct usb_endpoint_descriptor {
__u8 bLength __attribute__ ((packed));
__u8 bDescriptorType __attribute__ ((packed));
__u8 bEndpointAddress __attribute__ ((packed));
__u8 bmAttributes __attribute__ ((packed));
__le16 wMaxPacketSize __attribute__ ((packed));
__u8 bInterval __attribute__ ((packed));
__u8 bRefresh __attribute__ ((packed));
__u8 bSynchAddress __attribute__ ((packed));
unsigned char *extra ; /* Extra descriptors */
int extralen;
};
agar bagian awal struktur tidak mempunyai lubang memori sehingga dapat digunakan langsung untuk meletakkan data yang dibaca dari USB, tapi ruas extra dan extralen dibiarkan untuk ditata oleh kompailer agar akses data oleh program menjadi lebih cepat.

Tidak ada komentar: