alignas 지정자

alignas 지정자 (C++11)

메모리 정렬(alignment)을 특별히 지정해서, 그 타입이나 객체가 원하는 경계에 배치되도록 하고 싶을 때가 있어요. 그럴 때 쓰는 게 alignas 지정자예요. 이 페이지에서 alignas를 어디에, 어떻게 붙일 수 있는지, 그리고 자연 정렬과 충돌할 때 어떤 일이 생기는지 규칙 기준으로 정리해 볼게요.

출처: cppreference

본문

alignas는 타입이나 객체의 정렬 요구를 지정해요.

문법

alignas( expression )
alignas( type-id )
alignas( pack ... )
  1. expression정수 상수 표현식(integral constant expression)이어야 하고, 0으로 평가되거나 정렬(alignment)·확장 정렬(extended alignment)에 유효한 값으로 평가돼야 해요.
  2. alignas(alignof(type-id))와 동등해요.
  3. 같은 선언에 여러 alignas 지정자를 적용한 것과 동등해요. 매개변수 팩(parameter pack)의 각 멤버마다 하나씩인데, 타입 팩이나 비타입 팩일 수 있어요.

설명

alignas 지정자는 다음에 적용할 수 있어요.

  • 클래스의 선언이나 정의
  • 비트필드가 아닌 클래스 데이터 멤버의 선언
  • 변수의 선언 (다만 함수 매개변수, catch 절의 예외 매개변수에는 적용할 수 없어요)

그런 선언으로 선언된 객체나 타입은, 선언에 쓰인 모든 alignas 지정자 중 가장 엄격한(가장 큰) 0이 아닌 표현식과 같은 정렬 요구를 가져요. 단, 그게 타입의 자연 정렬을 약화시키지 않을 때예요.

선언에서 가장 엄격한(가장 큰) alignas가, alignas가 아예 없었을 때의 정렬(즉 자연 정렬, 또는 같은 객체·타입의 다른 선언에 있는 alignas)보다 약하다면 프로그램은 ill-formed예요.

struct alignas(8) S {};
struct alignas(1) U { S s; }; // error: alignas(1)이 없었다면 U의 정렬은 8이었음

alignas(3) 같은 유효하지 않은 0이 아닌 정렬은 ill-formed예요.

같은 선언에서 다른 alignas보다 약한 유효한 0이 아닌 정렬은 무시돼요.

alignas(0)은 항상 무시돼요.

주의

ISO C11 표준부터 C 언어에는 _Alignas 키워드가 있고, <stdalign.h> 헤더에서 alignas를 그 키워드로 확장하는 전처리기 매크로로 정의해요.

C++에서는 이게 키워드예요.

키워드

alignas

예시

#include <iostream>

// struct_float 타입의 모든 객체는
// alignof(float) 경계(보통 4)에 정렬:
struct alignas(float) struct_float
{
    // 여기에 정의
};

// sse_t 타입의 모든 객체는 32바이트 경계에 정렬:
struct alignas(32) sse_t
{
    float sse_data[4];
};

int main()
{
    struct default_aligned
    {
        float data[4];
    } a, b, c;
    sse_t x, y, z;

    std::cout
        << "alignof(struct_float) = " << alignof(struct_float) << '\n'
        << "sizeof(sse_t) = " << sizeof(sse_t) << '\n'
        << "alignof(sse_t) = " << alignof(sse_t) << '\n'
        << std::hex << std::showbase
        << "&a: " << &a << "\n"
           "&b: " << &b << "\n"
           "&c: " << &c << "\n"
           "&x: " << &x << "\n"
           "&y: " << &y << "\n"
           "&z: " << &z << '\n';
}

가능한 출력:

alignof(struct_float) = 4
sizeof(sse_t) = 32
alignof(sse_t) = 32
&a: 0x7fffcec89930
&b: 0x7fffcec89940
&c: 0x7fffcec89950
&x: 0x7fffcec89960
&y: 0x7fffcec89980
&z: 0x7fffcec899a0

주소값은 실행 환경에 따라 달라져요. 여기서 눈여겨볼 점은 sse_t 객체들이 32바이트 경계(0x...960, 0x...980, 0x...9a0)에 배치돼 있고, 기본 정렬 구조체 객체들은 16바이트 간격(0x...930, 0x...940, 0x...950)으로 배치되어 있다는 거예요.

더 알아보기

  • 객체의 정렬 요구를 읽는 alignof 연산자와 짝을 이뤄요.
  • 정렬(alignment)의 의미와 속성은 정렬 문서에서 자세히 볼 수 있어요.
  • cppreference의 alignas 원문에서 결함 보고 기록을 더 볼 수 있어요.