`_Alignas`/`alignas` 정렬 지정자

_Alignas/alignas 정렬 지정자

어떤 객체를 메모리에서 더 큰 정렬 경계에 배치하고 싶을 때가 있어요. 예를 들어 캐시라인 단위로 정렬된 배열을 만들고 싶다거나요. 그럴 때 선언 구문에서 타입 지정자 자리에 붙여서 객체의 정렬 요구(alignment requirement)를 바꿔주는 게 _Alignas(C23부터는 alignas) 지정자예요.

출처: cppreference

본문

_Alignas(C23 이후는 alignas)는 선언되는 객체의 정렬 요구를 수정하는 타입 지정자 중 하나로 선언 구문에 등장해요.

문법

_Alignas ( expression ) (1) (since C11)
alignas ( expression ) (2) (since C23)
_Alignas ( type ) (3) (since C11)
alignas ( type ) (4) (since C23)
expression - 값이 유효한 정렬이거나 0인 정수 상수 표현식
type - 아무 타입 이름

참고: C23 이전에는 _Alignas 키워드가 <stdalign.h> 헤더의 편의 매크로 alignas로도 쓸 수 있었어요.

설명

_Alignas(C23 이후 alignas) 지정자는 비트필드가 아니면서 register 저장소 클래스를 갖지 않는 객체를 선언할 때만 쓸 수 있어요. 함수 매개변수 선언에는 쓸 수 없고, typedef에도 쓸 수 없어요.

선언에서 이 지정자를 쓰면, 선언되는 객체의 정렬 요구는 다음과 같이 정해져요.

1,2) expression의 값 (0이 아니면) 3,4) type의 정렬 요구, 즉 _Alignof(type)(C23 이후 alignof(type))

단, 이렇게 해서 타입이 원래 자연스럽게 가졌을 정렬보다 약해지는 경우는 예외예요. expression이 0으로 평가되면 이 지정자는 아무 효과가 없어요.

같은 선언에 _Alignas(C23 이후 alignas)가 여러 번 등장하면, 가장 엄격한(가장 큰) 것이 적용돼요.

_Alignas(C23 이후 alignas) 지정자는 객체의 정의에만 등장해도 되지만, 어떤 선언에서 이 지정자를 쓴다면 정의에서 쓴 것과 같은 정렬을 명시해야 해요. 서로 다른 번역 단위가 같은 객체에 대해 다른 정렬을 지정하면 동작은 정의되지 않아요(undefined behavior).

주의

C++에서는 alignas 지정자를 class/struct/union 타입과 열거형의 선언에도 적용할 수 있어요. C에서는 그게 지원되지 않지만, 멤버 선언에 _Alignas(C23 이후 alignas)를 써서 struct 타입의 정렬을 조절할 수는 있어요.

키워드

alignas, _Alignas

예시

struct sse_t 타입의 모든 객체를 16바이트 경계에, struct data 타입의 모든 객체를 128바이트 경계에 정렬하는 코드예요.

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

// every object of type struct sse_t will be aligned to 16-byte boundary
// (note: needs support for DR 444)
struct sse_t
{
    alignas(16) float sse_data[4];
};

// every object of type struct data will be aligned to 128-byte boundary
struct data
{
    char x;
    alignas(128) char cacheline[128]; // over-aligned array of char,
                                      // not array of over-aligned chars
};

int main(void)
{
    printf("sizeof(data) = %zu (1 byte + 127 bytes padding + 128-byte array)\n",
           sizeof(struct data));

    printf("alignment of sse_t is %zu\n", alignof(struct sse_t));

    alignas(2048) struct data d; // this instance of data is aligned even stricter
    (void)d; // suppresses "maybe unused" warning
}

출력:

sizeof(data) = 256 (1 byte + 127 bytes padding + 128-byte array)
alignment of sse_t is 16

여기서 눈여겨볼 점은 alignas(16)이 붙은 sse_data 멤버 덕분에 struct sse_t의 정렬이 16으로 잡힌다는 거예요. 또 alignas(2048)은 지역 변수 하나에 더 엄격한 정렬을 적용하는 예시죠.

결함 보고

이전 C 표준에 소급 적용된 동작 변경 결함 보고는 다음과 같아요.

DR 적용 대상 게시된 동작 올바른 동작
DR 444 C11 _Alignas는 struct/union 멤버에서 허용되지 않았음 허용됨

더 알아보기

  • 객체의 정렬 요구를 읽어내는 _Alignof/alignof 연산자와 짝을 이뤄요.
  • 정렬(alignment)의 개념과 규칙은 객체와 정렬 문서에서 더 자세히 볼 수 있어요.
  • cppreference의 alignas 원문에서 결함 보고 기록을 더 확인할 수 있어요.