Lompat ke konten Lompat ke sidebar Lompat ke footer

Anggota Structure, Padding, dan Data Packing Bahasa C

Pada artikel ini akan dipelajari tentang data alignment, structure packing dan padding pada Bahasa C.

Anggota Structure, Padding, dan Data Packing Bahasa C
StructPadding, dan Data Packing Bahasa C

Sebelum memahami lebih dalam materi tentang Anggota Structure, Padding, dan Data Packing Bahasa C, terlebih dahulu pelajari materi tentang: Struct Hack Bahasa C dan Penjelasannya [klik], Union Bahasa C dan Penjelasannya [klik], dan Struct Bahasa C dan Penjelasannya [klik].

Contoh: Perkirakan hasil output dari contoh program berikut.

#include <stdio.h>


// Alignment requirements

// (typical 32 bit machine)


// char 1 byte

// short int 2 bytes

// int 4 bytes

// double 8 bytes


// struct A


typedef struct structa_tag

{

char c;

short int s;

} structa_t;



// Struct B

typedef struct structb_tag

{

short int s;

char c;

int i;

} structb_t;


// Struct C

typedef struct structc_tag

{

char c;

double d;

int s;

} structc_t;


// Struct D

typedef struct structd_tag

{

double d;

int s;

char c;

} structd_t;


int main()

{


printf("sizeof(structa_t) = %lu\n",

sizeof(structa_t));


printf("sizeof(structb_t) = %lu\n",

sizeof(structb_t));


printf("sizeof(structc_t) = %lu\n",

sizeof(structc_t));


printf("sizeof(structd_t) = %lu\n",

sizeof(structd_t));


return 0;

}


Data Alignment:
Setiap tipe data pada Bahasa C dan C++ selalu memiliki persaraan alignment pada penggunaannya. Sebuah prosesor akan memproses nilai panjang huruf sama seperti nilai ukuran data bus-nya. Pada komputer dengan prosesor 32, maka proses ukuran kata akan mengambil nilai memori sebesar 4 bytes.

Awalnya, memori merupakan alamat byte yang diatur secara sekuensial. Jika memori yang telah diatur sebagai sebuah bank atau penampung tunggal dari satu buah lebar byte, maka prosesor membutuhkan hal tersebut untuk untuk mengeluarkan 4 siklus baca memori untuk mengambil integer. Hal ini jauh lebih efisien untuk membaca semua ukuran 4 bytes integer pada perputaran memori yang digunakan. Untuk lebih jauh, suatu memori akan diatur dalam suatu kelompok yang terdiri dari 4 buah penampung.


Suatu alamat memori akan selalu diurutkan secara sekuensial, jika nilai penampung adalah 0 yang menempati alamat X, maka penampung 1, penampung 2, dan penampung 3 akan berada di alamat (X + 1), (X + 2) dan (X + 3). Jika integer 4 byte dialokasikan pada alamat X yang merupakan kelipatan dari nilai 4, maka prosesor hanya memerlukan satu siklus memori untuk membaca seluruh bilangan bulat. Sedangkan, jika bilangan bulat dialokasikan pada alamat selain kelipatan 4, maka bilangan bulat tersebut akan membentang di dua baris penampung, dimana tipe integer tersebut membutuhkan dua siklus baca memori untuk mengambil data.

Sebuah variabel data alignmt berhadapan dengan sebuah jalur data yang disimpan pada penampung tersebut. Contoh, nilai perataan natural dari int pada komputer 32-bit adalah 4 bytes. Ketika sebuah tipe data secara alami telah diratakan, maka CPU akan melakukan fetch pada nilai perputaran minimum.

Hal tersebut sama halnya dengan nilai perataan alami dari short int sebesar 2 bytes. Hal ini berarti bahwa sebuah short int dapat disimpan pada penampung 0 – penampung bank 1 atau penampung 2 dan atau penampung 3. Sebuah nilai double pada tipe data membutuhkan ukuran memori sebesar 8 bytes, atau setara dua nilai baris pada memori penampung. Setiap nilai perataan yang salah atau misalignment dari nilai double akan memaksa dua proses perputara untuk fetch data double.

Catatan: sebuah variabel dengan nilai double akan dialokasikan pada nilai memori sebesar 8 byte pada tipe prosesor 32 bit dan membutuhkan dua proses perputaran memori. Sedangkan pada prosesor tipe 64, berdasarkan nilai dari penampung, dimana variabel dengan tipe double akan dialokasikan pada nilai 8 byte dan hanya membutuhkan satu kali proses perputaran baca memori.

Structure Padding:
Pada bahasa C dan C++ sebuah structure digunakan untuk melakukan pembungkusan data atau data pack. Hal ini tidak menyediakan proses enkapsulasi data apapun atau penyembunyian fitur data apapun, sedangkan pada C++ terjadi pengecualian terhadap nilai semantik yang sama dengan class. Karena persyaratan nilai alignment dari verbagai tipe ata, maka setiap anggota struct harus secara alami telah diratakan, dimana anggota dari struct dialokasikan urut secara meningkat.

Untuk kenyamanan, asumsikan setiap tipe struct dari variabel dialokasikan ke tipe ukuran 4 byte seperti 0x0000), dan seterusnya. Nilai dasar alamat dari struct kemudian dilipatgandakan dari angga 4, walaupun sifatnya tidak selalu dibutuhkan.

Structure A
Elemen pertama structa_t first adalah tipe char yang merupakan one byte perataan, yang diikuti dengan nilai short int. short int adalah 2 byte nilai perataan. Jika nilai elemen hort int elemen segera dialokasikan setelah nilai elemen char, maka hal tersebut akan dimulai pada nilai alamat pada angka ganjil. Kompilator kemudian akan memasukkan sebuah padding byte setelah nilai char untuk memastikan bahwa nilai short int akan memiliki nilai alamat berkalilipat dari kelipatan 2. Nilai total dari structa_t merupakan ukuran dari sizeof(char) + 1 (padding) + sizeof(short), 1 + 1 + 2 = 4 bytes.

Structure B
Anggota pertama dari structb_t adalah short int yang diikuti oleh nilai char. Karena char dapat berada pada batas byte apa pun, maka tidak diperlukan padding di antara nilai short int dan char, sehingga totalnya menempati nilai 3 byte. Anggota berikutnya adalah int. Jika int dialokasikan secara segera, maka hal tersebut akan dimulai pada batas byte ganjil. Dibutuhkan 1 byte padding setelah anggota char untuk membuat alamat anggota int berikutnya selaras dengan nilai 4 byte. Secara total, structb_t membutuhkan 2 + 1 + 1 (padding) + 4 = 8 byte.

Structure C – Setiap struct akan memiliki nilai persyaratan alignment
Menerapkan analisis yang sama, structc_t membutuhkan sizeof (char) + 7 byte padding + sizeof (double) + sizeof (int) = 1 + 7 + 8 + 4 = 20 byte. Namun, sizeof (structc_t) akan menjadi 24 byte. Oleh karena itu, bersama dengan anggota struct, variabel tipe struct juga akan memiliki keselarasan alami. 

Contoh, dideklarasikan array structc_t seperti yang ditunjukkan berikut:

structc_t structc_array[3];

Asumsikan alamat dasar structc_array adalah 0x0000 untuk perhitungan yang mudah. Jika structc_t menempati 20 (0x14) byte seperti yang dihitung, maka elemen array structc_t kedua (diindeks pada 1) akan berada pada 0x0000 + 0x0014 = 0x0014. Ini adalah alamat awal elemen array indeks 1. Anggota double dari structc_t ini akan dialokasikan pada 0x0014 + 0x1 + 0x7 = 0x001C (desimal 28) yang bukan kelipatan 8 dan bertentangan dengan persyaratan penyelarasan double. Seperti yang disebutkan sebelumnya, bahwa persyaratan penyelarasan double adalah 8 byte.

Untuk menghindari ketidaksejajaran seperti hal tersebut, maka kompilator akan memperkenalkan persyaratan penyelarasan ke setiap struct yang digunakn. Dimana hal ini akan menjadi anggota struktur terbesar. Dalam kasus penyelarasan structa_t nilai yan digunakan adalah 2, structb_t adalah 4 dan structc_t adalah 8. Jika kita membutuhkan nested struct, maka ukuran struct dalam terbesar akan menjadi penyelarasan langsung dari struktur yang lebih besar.

Dalam structc_t dari program yang dijelaskan sebelumnya, akan ada padding 4 byte setelah anggota int untuk membuat ukuran struktur kelipatan dari perataannya. Jadi, ukuran (structc_t) adalah 24 byte, dimana hal ini dapat menjamin keselarasan yang benar bahkan dalam array.

Structure D – Cara mengurangi padding.
Telah dipahami bahwa penggunaan padding merupakan sesuatu yang tidak dapat dihindari pada Bahasa C. Namun ada cara untuk meminimalkan penggunaan padding tersebut pada Bahasa C, dimana Pemrogram harus mendeklarasikan anggota struktur dalam urutan peningkatan atau penurunan nilai ukurannya. Contohnya adalah structd_t yang diberikan dalam kode dengan nilai ukuran 16 byte sebagai nilai pengganti 24 byte structc_t.

Structure Packing
Terkadang merupakan suatu hal yang wajih dilakukan untuk menghindari penggunaan padding yang terdapat diantara anggota struct. Misalnya membaca isi header file ELF atau header file BMP atau JPEG. Untuk melakukan hal tersebut maka diperlukan pendefinisian struct yang mirip dengan tata letak tajuk dan memetakannya. Namun, kehati-hatian harus selalu dilakukan dalam mengakses anggota tersebut. Biasanya membaca byte demi byte adalah opsi untuk menghindari pengecualian yang tidak selaras, dimana akan ada hit pada kinerja yang dilakukan tersebut. Untuk mengatasi hal tersebut, sebagian besar kompilator menyediakan ekstensi non standar untuk mematikan padding default seperti pragma atau command line switches.

Pointer Mishaps:
Ada kemungkinan terjadinya kesalahan potensial saat menangani aritmatika pointer. Misalnya, mendereferensi pointer generik (void *) seperti yang ditunjukkan di bawah ini dapat menyebabkan pengecualian yang tidak selaras,

// Dereferensi pointer generic dengan cara tidak aman, dimana tidak terdapat jaminan bahwa pointer generic akan menghasilkan nila perataan integer.
*(int *)pGeneric;

Jika pointer pGeneric tidak sejajar sesuai persyaratan tipe data, maka ada kemungkinan untuk mendapatkan pengecualian yang tidak selaras. Faktanya beberapa prosesor tidak akan memiliki dua bit terakhir dari nilai decoding alamat, dan tidak ada cara untuk mengakses alamat yang tidak selaras, dimana prosesor akan menghasilkan pengecualian yang tidak selaras, jika pemrogram mencoba mengakses alamat tersebut.

Sebuah Catatan pada malloc() Returned Pointer
Pointer yang dikembalikan oleh malloc() adalah void *. Hal ini dapat dikonversi ke tipe data apa pun sesuai kebutuhan programmer. Pelaksana malloc() harus mengembalikan pointer yang disejajarkan dengan ukuran maksimum tipe data primitif yang telah ditentukan oleh kompilator. Biasanya disejajarkan dengan batas 8 byte pada mesin 32 bit.


Artikel ini didedikasikan kepada: Cuwi Nurti Ningrum, David Aldi Ramadhani, Diska Choirunnisa, Dwi Setyawan, dan Erlinda Suastika Dewi.

16 komentar untuk "Anggota Structure, Padding, dan Data Packing Bahasa C"

  1. Apakah alignment diterapkan untuk stack pada Bahasa C?

    BalasHapus
    Balasan
    1. Ya, karena stack juga merupakan memori. Pemrogram sistem harus memuat pointer stack dengan alamat memori yang disejajarkan dengan benar. Umumnya, prosesor tidak akan memeriksa penjajaran stack, yang merupakan tanggung jawab pemrogram untuk memastikan penyelarasan yang tepat dari memori stack. Setiap misalignment akan menyebabkan kejutan waktu berjalan. Misalnya, jika panjang kata prosesor adalah 32 bit, maka pointer stack juga harus disejajarkan menjadi kelipatan 4 byte.

      Hapus
  2. Bagaimana prosesor menangani tipe char Bahasa C?

    BalasHapus
    Balasan
    1. Jika data char ditempatkan di penampung lain, seperti penampung 0, maka hal tersebut akan membuah nilai ditempatkan pada jalur data yang salah selama pembacaan memori. Biasanya prosesor akan mengenali tipe data berdasarkan instruksi seperti LDRB pada prosesor ARM. Bergantung pada tempat penyimpanannya, dimana prosesor akan menggeser byte ke jalur data yang paling tidak signifikan.

      Hapus
  3. Ketika argumen diteruskan pada stack, apakah stack tersebut akan tunduk pada alignment Bahasa C?

    BalasHapus
    Balasan
    1. Ya. Kompilator akan membantu programmer dalam membuat keselarasan yang tepat. Misalnya, jika nilai 16-bit didorong ke stack selebar 32-bit, dimana nilainya secara otomatis diisi dengan nol hingga 32 bit. Perhatikan program berikut.

      Hapus
    2. void argument_alignment_check( char c1, char c2 )

      {

      // Downward stack

      // (on upward stack the output will be negative)

      printf("Displacement %d\n", (int)&c2 - (int)&c1);

      }

      Hapus
    3. Outputnya akan menjadi 4 pada prosesor tipe 32 bit. Hal tersebut terjadi karena setiap karakter akan menempati 4 byte karena persyaratan penyelarasan.

      Hapus
  4. Apa yang akan terjadi jika mencoba untuk mengakses sebuah misaligned data pada Bahasa C?

    BalasHapus
    Balasan
    1. Hal tersebut bergantung pada arsitektur prosesor. Jika akses tidak selaras, maka prosesor secara otomatis mengeluarkan siklus baca memori yang cukup dan mengemas data dengan benar ke dalam bus data. Hukumannya ada pada kinerja. Di mana beberapa prosesor tidak akan memiliki dua baris alamat terakhir, yang berarti tidak ada cara untuk mengakses batas byte ganjil, dimana setiap akses data harus selaras (4 byte) dengan benar. Akses yang tidak selaras adalah pengecualian penting pada prosesor tersebut. Jika pengecualian diabaikan, maka data yang dibaca akan salah dan menyebabkan error.

      Hapus
  5. Apakah ada cara untuk menanyakan persyaratan penyelarasan atau alignment dari tipe data pada Bahasa C?

    BalasHapus
    Balasan
    1. Ya. Kompilator menyediakan ekstensi non standar untuk kebutuhan tersebut. Misalnya, __alignof() di Visual Studio yang dapat membantu mendapatkan persyaratan penyelarasan tipe data.

      Hapus
  6. Ketika pembacaan memori efisien dalam membaca 4 byte sekaligus pada mesin 32 bit, mengapa tipe ganda harus disejajarkan pada batas 8 byte pada Bahasa C?

    BalasHapus
    Balasan
    1. Penting untuk dicatat bahwa sebagian besar prosesor akan memiliki co-processor matematis, yang disebut Floating Point Unit (FPU). Setiap operasi floating point dalam kode akan diterjemahkan ke dalam instruksi FPU. Prosesor utama tidak ada hubungannya dengan eksekusi floating point. Semua ini akan dilakukan di belakang layar.

      Hapus
    2. Sesuai standar, tipe ganda akan menempati 8 byte. Dan, setiap operasi floating point yang dilakukan di FPU akan memiliki panjang sebesar 64 bit, bahkan tipe float akan dipromosikan ke 64 bit sebelum dieksekusi.

      Hapus
    3. Panjang 64 bit register FPU memaksa tipe ganda atau double untuk dialokasikan pada batas 8 byte. Misal diasumkan tidak memiliki informasi konkret dalam hal operasi FPU, maka pengambilan data yang dihasilkan mungkin berbeda, karena masuk ke FPU. Oleh karena itu, decoding alamat akan berbeda untuk tipe double yang diharapkan berada pada batas 8 byte. Artinya, sirkuit decoding alamat unit floating point tidak akan memiliki 3 pin terakhir.

      Hapus

Hubungi admin melalui Wa : +62-896-2414-6106

Respon komentar 7 x 24 jam, mohon bersabar jika komentar tidak langsung dipublikasi atau mendapatkan balasan secara langsung.

Bantu admin meningkatkan kualitas blog dengan melaporkan berbagai permasalahan seperti typo, link bermasalah, dan lain sebagainya melalui kolom komentar.

- Ikatlah Ilmu dengan Memostingkannya -
- Big things start from small things -