Alignment adalah persyaratan bahwa alamat memori suatu objek harus kelipatan tertentu. Misalnya, int di x86-64 memiliki alignment 4 byte—alamat harus habis dibagi 4. CPU dapat membaca int yang ter-align dengan satu instruksi, tetapi int yang tidak ter-align mungkin memerlukan dua instruksi atau memicu alignment fault pada arsitektur tertentu. C11 menyediakan _Alignas untuk memaksa alignment yang lebih besar dan _Alignof (alias alignof) untuk menanyakan alignment tipe. Header <stdalign.h> menyediakan alias alignas/alignof. Pada chapter ini kita akan memeriksa alignment berbagai tipe dan mengalokasikan buffer dengan alignment khusus lewat aligned_alloc.

Memeriksa Alignment dengan alignof #

Operator alignof(T) mengembalikan alignment requirement tipe T dalam byte. Operator ini adalah alias alignof untuk _Alignof (disediakan <stdalign.h>).

c
#include <stdio.h>
#include <stdalign.h>
#include <stdint.h>

int main(void) {
    /* _Alignof / alignof: query alignment requirement */
    printf("alignof(char)   = %zu\n", alignof(char));
    printf("alignof(short)  = %zu\n", alignof(short));
    printf("alignof(int)    = %zu\n", alignof(int));
    printf("alignof(double) = %zu\n", alignof(double));
    printf("alignof(int64_t)= %zu\n", alignof(int64_t));

    /* _Alignas: paksa alignment lebih besar */
    _Alignas(16) int x = 42;
    printf("alamat x (harus kelipatan 16): %p\n", (void *)&x);
    printf("alamat &x mod 16 = %zu\n", (size_t)((uintptr_t)&x % 16));

    /* Struct dengan alignment default */
    struct Vec4 {
        float v[4];
    };
    printf("sizeof(Vec4) = %zu, alignof(Vec4) = %zu\n",
           sizeof(struct Vec4), alignof(struct Vec4));

    /* Variabel struct dengan alignment 32 */
    _Alignas(32) struct Vec4 vec;
    printf("alamat vec (mod 32) = %zu\n", (size_t)((uintptr_t)&vec % 32));

    return 0;
}

Output yang Dihasilkan:

text
alignof(char)   = 1
alignof(short)  = 2
alignof(int)    = 4
alignof(double) = 8
alignof(int64_t)= 8
alamat x (harus kelipatan 16): 0x7fffe72caff0
alamat &x mod 16 = 0
sizeof(Vec4) = 16, alignof(Vec4) = 4
alamat vec (mod 32) = 0

Mari kita telaah baris-baris kode di atas:

  1. Baris 7-11 (alignof(char), dst.): menanyakan alignment tipe primitif. char memiliki alignment 1 (boleh di alamat mana pun), int 4 (harus kelipatan 4), double 8. Nilai-nilai ini berbeda per arsitektur—di ARM 32-bit lama, double bisa ber-alignment 4.
  2. Baris 14 (_Alignas(16) int x = 42;): memaksa alignment x menjadi 16, lebih besar dari int aslinya (4). Compiler akan menempatkan x di alamat yang habis dibagi 16.
  3. Baris 15-16 (cetak alamat dan modulo): verifikasi bahwa alamat &x habis dibagi 16. Pada output, modulo 0 menunjukkan alignment terpenuhi.
  4. Baris 19-22 (struct Vec4 { float v[4]; };): struct berisi 4 float (4 byte masing-masing) = 16 byte total. Alignment struct adalah alignment dari field dengan alignment terbesar, yaitu float = 4.
  5. Baris 25 (_Alignas(32) struct Vec4 vec;): variabel struct dengan alignment 32—lebih besar dari alignment default struct (4). Berguna bila struct akan dipakai di SIMD yang mensyaratkan alignment 32 byte (AVX).

Alokasi Aligned dengan aligned_alloc #

C11 menyediakan aligned_alloc(alignment, size) di <stdlib.h> untuk mengalokasikan blok memori dengan alignment yang ditentukan. Syaratnya: size harus kelipatan alignment.

c
#include <stdio.h>
#include <stdlib.h>
#include <stdalign.h>
#include <stdint.h>

/* aligned_alloc: alokasi buffer dengan alignment kuat */
int main(void) {
    size_t alignment = 64;   /* cacheline size typical x86 */
    size_t count = 16;      /* jumlah elemen */
    size_t bytes = count * sizeof(int);

    /* Round up bytes ke kelipatan alignment (syarat aligned_alloc) */
    size_t aligned_bytes = ((bytes + alignment - 1) / alignment) * alignment;

    int *buf = aligned_alloc(alignment, aligned_bytes);
    if (!buf) { perror("aligned_alloc"); return 1; }

    printf("alignment = %zu, bytes = %zu (rounded)\n", alignment, aligned_bytes);
    printf("alamat buf = %p\n", (void *)buf);
    printf("alamat mod alignment = %zu\n", (size_t)((uintptr_t)buf % alignment));

    /* Inisialisasi dan cetak */
    for (size_t i = 0; i < count; i++) buf[i] = (int)(i + 1);
    printf("buf[0..3] = %d %d %d %d\n", buf[0], buf[1], buf[2], buf[3]);

    free(buf);
    return 0;
}

Output yang Dihasilkan:

text
alignment = 64, bytes = 64 (rounded)
alamat buf = 0x561bd3252040
alamat mod alignment = 0
buf[0..3] = 1 2 3 4

Fungsi aligned_alloc menerima dua parameter: alignment dan ukuran. Pada contoh, kita mengalokasikan buffer 64 byte dengan alignment 64—sesuai dengan cacheline size pada x86-64. Buffer aligned berguna untuk SIMD (AVX-512 mensyaratkan 64 byte), DMA transfer, dan komunikasi dengan hardware tertentu.

Kapan Alignment Penting #

  • SIMD (SSE/AVX): instruksi vector mensyaratkan data ter-aligned 16/32/64 byte. Akses tidak ter-aligned memicu general protection fault.
  • DMA transfer: hardware DMA sering memerlukan alamat kelipatan 4 atau 8 byte.
  • Atomic operations: beberapa operasi atomic pada tipe besar (misalnya int128_t) memerlukan alignment alami tipe tersebut.
  • Menghindari false sharing: pada multi-threading, menempatkan variabel yang sering diakses berbeda thread di cacheline berbeda mengurangi koherensi cache.