맞춤

C++의 하위 수준 기능 중 하나는 특정 하드웨어 아키텍처를 최대한 활용하기 위해 메모리 내 개체의 정확한 맞춤을 지정하는 기능입니다. 기본적으로 컴파일러는 클래스 및 구조체 멤버의 크기 값 boolchar 과 1 바이트 경계, short 2 바이트 경계, longfloatint4 바이트 경계 및 long doublelong longdouble8 바이트 경계에 정렬합니다.

대부분의 시나리오에서는 기본 맞춤이 이미 최적이므로 맞춤에 신경 쓰지 않아도 됩니다. 그러나 경우에 따라 데이터 구조에 대한 사용자 지정 맞춤을 지정하여 상당한 성능 향상 또는 메모리 절감을 달성할 수 있습니다. Visual Studio 2015 이전에는 Microsoft 관련 키워드(keyword) __alignof__declspec(align) 사용하고 기본값보다 큰 맞춤을 지정할 수 있습니다. Visual Studio 2015부터 최대 코드 이식성을 위해 C++11 표준 키워드(keyword) alignofalignas 사용해야 합니다. 새 키워드(keyword) Microsoft 특정 확장과 동일한 방식으로 작동합니다. 이러한 확장에 대한 설명서는 새 키워드(keyword) 적용됩니다. 자세한 내용은 연산자, alignas 지정자맞춤을 참조 alignof 하세요. C++ 표준은 대상 플랫폼의 컴파일러 기본값보다 작은 경계 맞춤에 대한 압축 동작을 지정하지 않으므로 이 경우 Microsoft #pragma pack 를 사용해야 합니다.

사용자 지정 맞춤을 사용하여 데이터 구조의 메모리 할당에 aligned_storage 클래스 를 사용합니다. aligned_union 클래스는 비휘발성 생성자 또는 소멸자를 사용하는 공용 구조체에 대한 맞춤을 지정하기 위한 것입니다.

맞춤 및 메모리 주소

맞춤은 숫자 주소 모듈로 2의 거듭제곱으로 표현된 메모리 주소의 속성입니다. 예를 들어 주소 0x0001103F 모듈로 4는 3입니다. 해당 주소는 4n+3에 맞춰진 것으로, 여기서 4는 선택한 2의 힘을 나타냅니다. 주소의 맞춤은 선택한 2의 힘에 따라 달라집니다. 동일한 주소의 모듈로 8은 7입니다. 맞춤이 Xn+0인 경우 주소가 X에 맞춰집니다.

CPU는 메모리에 저장된 데이터에 대해 작동하는 명령을 실행합니다. 데이터는 메모리의 주소로 식별됩니다. 단일 데이텀의 크기도 있습니다. 주소가 크기에 맞춰지면 자연스럽게 정렬된 데이텀을 호출합니다. 그렇지 않으면 잘못 정렬되었다고 합니다. 예를 들어 8바이트 부동 소수점 데이텀은 식별에 사용되는 주소에 8바이트 맞춤이 있는 경우 자연스럽게 정렬됩니다.

데이터 맞춤의 컴파일러 처리

컴파일러는 데이터 정렬을 방해하는 방식으로 데이터 할당을 시도합니다.

단순 데이터 형식의 경우 컴파일러에서 데이터 형식 크기(바이트)의 배수인 주소를 할당합니다. 예를 들어 컴파일러는 주소의 하위 2 비트를 0으로 설정하여 4의 배수인 형식 long 의 변수에 주소를 할당합니다.

또한 컴파일러는 구조체의 각 요소를 자연스럽게 맞추는 방식으로 구조체를 패딩합니다. 다음 코드 예제의 구조를 struct x_ 고려합니다.

struct x_
{
   char a;     // 1 byte
   int b;      // 4 bytes
   short c;    // 2 bytes
   char d;     // 1 byte
} bar[3];

컴파일러는 자연스럽게 맞춰지도록 이 구조를 채웁니다.

다음 코드 예제에서는 컴파일러가 패딩된 구조를 메모리에 배치하는 방법을 보여 줍니다.

// Shows the actual memory layout
struct x_
{
   char a;            // 1 byte
   char _pad0[3];     // padding to put 'b' on 4-byte boundary
   int b;            // 4 bytes
   short c;          // 2 bytes
   char d;           // 1 byte
   char _pad1[1];    // padding to make sizeof(x_) multiple of 4
} bar[3];

두 선언 모두 12바이트로 반환 sizeof(struct x_) 됩니다.

두 번째 선언에는 다음 두 개의 패딩 요소가 포함되어 있습니다.

  1. char _pad0[3] 4 바이트 경계에 멤버를 정렬 int b 합니다.
  2. char _pad1[1] 구조체의 struct _x bar[3]; 배열 요소를 4 바이트 경계에 맞추려면

안쪽 여백은 자연 액세스를 허용하는 방식으로 요소를 bar[3] 정렬합니다.

다음 코드 예제에서는 배열 레이아웃을 bar[3] 보여줍니다.

adr offset   element
------   -------
0x0000   char a;         // bar[0]
0x0001   char pad0[3];
0x0004   int b;
0x0008   short c;
0x000a   char d;
0x000b   char _pad1[1];

0x000c   char a;         // bar[1]
0x000d   char _pad0[3];
0x0010   int b;
0x0014   short c;
0x0016   char d;
0x0017   char _pad1[1];

0x0018   char a;         // bar[2]
0x0019   char _pad0[3];
0x001c   int b;
0x0020   short c;
0x0022   char d;
0x0023   char _pad1[1];

alignofalignas

alignas 지정자는 변수 및 사용자 정의 형식의 사용자 지정 맞춤을 지정하는 이식 가능한 C++ 표준 방법입니다. alignof 마찬가지로 연산자는 지정된 형식 또는 변수의 맞춤을 가져오는 표준 이식 가능한 방법입니다.

예시

클래스, 구조체 또는 공용 구조체 또는 개별 멤버에서 사용할 alignas 수 있습니다. 여러 alignas 지정자가 발견되면 컴파일러는 값이 가장 큰 지정자를 선택합니다.

// alignas_alignof.cpp
// compile with: cl /EHsc alignas_alignof.cpp
#include <iostream>

struct alignas(16) Bar
{
    int i;       // 4 bytes
    int n;      // 4 bytes
    alignas(4) char arr[3];
    short s;          // 2 bytes
};

int main()
{
    std::cout << alignof(Bar) << std::endl; // output: 16
}

참고 항목

데이터 구조 맞춤