Table of Contents

stdalign.h

stdalign.h (C11) gives you alignas and alignof — the convenient macro wrappers around the _Alignas and _Alignof keywords. Alignment controls where in memory an object is placed: a 16-byte-aligned object must start at an address divisible by 16. You need this most often for SIMD, where vector load instructions require specific alignment, and occasionally for hardware registers.

#include <stdalign.h>
 
alignas(16) float vec[4];   // guaranteed 16-byte aligned, safe for SSE loads
 
printf("alignof(double) = %zu\n", alignof(double));  // typically 8
printf("alignof(char)   = %zu\n", alignof(char));    // always 1

alignof(type) returns the required alignment of type as a size_t. alignas(n) on a declaration forces the object to be placed at a multiple of n bytes.

The most common use is SIMD buffers on x86:

// AVX loads require 32-byte alignment for the aligned variant
alignas(32) float a[8], b[8], result[8];
// __m256 va = _mm256_load_ps(a);  // safe: guaranteed aligned

alignas can also take a type as its argument: alignas(double) char buf[sizeof(double)] gives a char array with the same alignment as double, which is useful for manual object placement.

Practice

// compile: gcc -o aligndemo aligndemo.c
// run: ./aligndemo
// description: verify alignas places buffers at the promised boundaries
 
#include <stdalign.h>
#include <stdio.h>
#include <stdint.h>
 
int main(void) {
    alignas(1)  char  a;
    alignas(4)  int   b;
    alignas(16) float vec4[4];
    alignas(32) float vec8[8];
 
    printf("alignof(char)  = %zu  &a    addr mod 1  = %zu\n",
           alignof(char),  (uintptr_t)&a    % 1);
    printf("alignof(int)   = %zu  &b    addr mod 4  = %zu\n",
           alignof(int),   (uintptr_t)&b    % 4);
    printf("vec4 addr mod 16 = %zu  (should be 0)\n", (uintptr_t)vec4  % 16);
    printf("vec8 addr mod 32 = %zu  (should be 0)\n", (uintptr_t)vec8  % 32);
    return 0;
}

All the mod results should be 0. Try removing one of the alignas specifiers and check whether the address still happens to be aligned — it often is due to the compiler's own alignment decisions, but you cannot rely on that without the explicit declaration.