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.
// 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.