메모리 정렬 : alignof / alignas를 사용하는 방법?


82

저는 지금 공유 메모리로 작업합니다.

나는 이해할 수 없다 alignof하고 alignas.

cppreference 가 명확하지 않습니다. alignof"alignment"를 반환하지만 "alignment"는 무엇입니까? 정렬 할 다음 블록을 위해 추가 할 바이트 수? 패딩 사이즈? 스택 오버플로 / 블로그 항목도 명확하지 않습니다.

사람이 명확하게 설명 할 수 alignofalignas?


1
cppreference은 자습서가 아닌 참조가 될하려고
Cubbi

1
@Cubbi : 당신은 또한 cplusplus.com에서 확인할 수 있습니다, 사이트가 다른 cppreference이 더 나은, 나는이 두 사이트 특정 시간이 eonugh 아니라는 것을 발견, CPLUSPLUS이 더 특정 주제, 더 느릅 나무 논쟁이
CoffeDeveloper

2
cppreference가에 정렬의 개념을 설명하지 않는 이유 @DarioOO 난 단지 응답 한 alignof페이지를 (가 업무 진행에, 지금 않는 객체 페이지 ). cplusplus.com이 얼마나 관련이 있는지 모르겠습니다.
Cubbi

답변:


82

정렬은 값의 첫 번째 바이트가 저장 될 수있는 메모리 위치에 대한 제한입니다. (프로세서의 성능을 향상시키고 특정 정렬이있는 데이터에서만 작동하는 특정 명령어의 사용을 허용하는 데 필요합니다. 예를 들어 SSE는 16 바이트로 정렬되고 AVX는 32 바이트로 정렬해야합니다.)

16의 정렬은 16의 배수 인 메모리 주소가 유일한 유효한 주소임을 의미합니다.

alignas

필요한 바이트 수로 강제 정렬합니다. 2 : 1, 2, 4, 8, 16, 32, 64, 128, ...의 거듭 제곱으로 만 정렬 할 수 있습니다.

#include <cstdlib>
#include <iostream>

int main() {
    alignas(16) int a[4];
    alignas(1024) int b[4];
    printf("%p\n", a);
    printf("%p", b);
}

예제 출력 :

0xbfa493e0
0xbfa49000  // note how many more "zeros" now.
// binary equivalent
1011 1111 1010 0100 1001 0011 1110 0000
1011 1111 1010 0100 1001 0000 0000 0000 // every zero is just a extra power of 2

다른 키워드

alignof

매우 편리합니다.

int a[4];
assert(a % 16 == 0); // check if alignment is to 16 bytes: WRONG compiler error

하지만 당신은 할 수 있습니다

assert(alignof(a) == 16);
assert(alignof(b) == 1024);

실제로 이것은 단순한 "%"(모듈러스) 연산보다 더 엄격합니다. 사실 우리는 1024 바이트로 정렬 된 것이 반드시 1, 2, 4, 8 바이트로 정렬된다는 것을 알고 있지만

 assert(alignof(b) == 32); // fail.

더 정확하게 말하자면, "alignof"는 어떤 것이 정렬 될 때 가장 큰 2의 거듭 제곱을 반환합니다.

또한 alignof는 기본 데이터 유형에 대한 최소 정렬 요구 사항을 미리 알 수있는 좋은 방법입니다 (아마도 문자의 경우 1, 부동의 경우 4를 반환합니다).

여전히 합법적 :

alignas(alignof(float)) float SqDistance;

16으로 정렬 된 항목은 16의 배수 인 다음 사용 가능한 주소에 배치됩니다 (마지막으로 사용 된 주소에서 암시 적 패딩이있을 수 있음).


10
달리 sizeof, alignof단지에 적용 할 수 있습니다 type-id.
neverhoodboy 2014

되고 alignof()(및 대응는 alignas()) 그래서 런타임 오버 헤드, 컴파일 시간에 평가되지?
무감각

아니. 컴파일러는이를 최적화하는 경우가 거의 없지만 일반적으로 두 함수를 평가하기 전에 메모리 주소가 정렬되는 방식을 알지 못합니다. 내 예제에서 생성 된 어셈블리를보십시오. goo.gl/ZbemBF
CoffeDeveloper

1
명확히하기 위해 @Serthy는 alignof 것입니다 컴파일 타임 상수. alignas그렇지 않으며 new(표준 요구 사항) 구현 또는 사용자 지정 std 할당 자에 의해 지원되어야합니다 .
Aidiakapi

좋은 대답은, 그러나 그것은 치료가 필요 struct하다 구조체의 및 회원 static. 특히 Clang과 같은 컴파일러에서는 alignas보다 훨씬 까다 __attribute__((aligned))롭습니다.
jww

11

정렬은 패딩이 아닙니다 (정렬 요구 사항을 충족하기 위해 패딩이 도입되는 경우도 있음). C ++ 유형의 intrisic 속성입니다. 표준에 넣으려면 ( 3.11[basic.align])

객체 유형에는 해당 유형의 객체가 할당 될 수있는 주소에 제한을 두는 정렬 요구 사항 (3.9.1, 3.9.2)이 있습니다. 정렬은 주어진 객체가 할당 될 수있는 연속 주소 사이의 바이트 수를 나타내는 구현 정의 정수 값입니다. 개체 유형은 해당 유형의 모든 개체에 대해 정렬 요구 사항을 부과합니다. 더 엄격한 정렬은 정렬 지정자 (7.6.2)를 사용하여 요청할 수 있습니다.


1
매우 흥미로운. 몇 가지 예를 들어 주시겠습니까? alignof (struct X) == sizeof (struct X)? 왜 안돼?
Offirmo 2013-06-13

1
@Offirmo 아니오, 간결함을 제외하고 : struct X { char a; char b}정상적인 시스템에서 크기 2 및 정렬 요구 사항 1이 있습니다 (문자는 모든 주소에 할당 될 수 있으므로 모든 주소에 할당 가능)
Cubbi

정렬 필요 1 ???? 오, 알겠습니다. 정렬은 항상 "자연스러운"32 비트 / 64 비트 경계에 있다고 생각했지만 분명히 그렇지 않았습니다. 그래서 일반적인 컴퓨터에서 alignof () 결과는 항상 4 (32 비트) 또는 8 (64 비트)에서 최대 값이됩니다. 맞습니까?
Offirmo

@Offirmo "natural"alignof는 내 리눅스에 alignof(std::max_align_t)있는 에서 최대 값을 얻습니다 16(-m32 또는 -m64 컴파일 여부에 관계없이),하지만 다음과 같이 더 엄격하게 만들 수 있습니다.alignas
Cubbi

7

각 유형에는 정렬 요구 사항이 있습니다. 일반적으로 이것은 데이터 유형의 주어진 구성원에 도달하기 위해 CPU가 둘 이상의 읽기 / 쓰기 액세스를 생성하지 않고도 유형의 변수에 효율적으로 액세스 할 수 있기 때문입니다. 또한 전체 변수를 효율적으로 복사 할 수 있습니다. alignof주어진 유형에 대한 정렬 요구 사항을 반환합니다.

alignas데이터 유형에 대한 정렬을 강제하는 데 사용됩니다 (해당 alignof데이터 유형이 반환 하는 것보다 덜 엄격하지 않은 한 ).


3

정렬은 메모리 주소와 관련된 속성입니다. 주소 X가 Z에 정렬되면 x는 Z의 배수, 즉 X = Zn + 0입니다. 여기서 중요한 것은 Z가 항상 2의 제곱이라는 것입니다.

정렬은 메모리 주소의 속성으로, 2의 거듭 제곱 모듈로 숫자 주소로 표현됩니다. 예를 들어, 주소 0x0001103F 모듈로 4는 3입니다.이 주소는 4n + 3으로 정렬됩니다. 여기서 4는 선택한 전원을 나타냅니다. 2. 주소의 정렬은 선택한 2의 거듭 제곱에 따라 달라집니다. 동일한 주소 모듈로 8은 7입니다. 주소가 Xn + 0이면 X에 정렬된다고합니다.

위의 문은 Microsoft C ++ 참조에서 찾을 수 있습니다.

데이터 항목이 크기에 맞는 주소로 메모리에 저장되면 해당 데이터 항목은 자연스럽게 정렬 된다고합니다. 되고 그렇지 않으면 잘못 . 예를 들어, 크기가 4 바이트 인 정수 변수가 4로 정렬 된 주소에 저장되면 변수가 자연적으로 정렬된다고 말할 수 있습니다. 즉, 변수의 주소는 4의 배수 여야합니다.

컴파일러는 항상 오정렬을 피하기 위해 노력합니다. 단순 데이터 유형의 경우 주소는 변수 크기 (바이트)의 배수가되도록 선택됩니다. 컴파일러는 또한 자연적인 정렬과 접근을위한 구조의 경우 적절하게 채 웁니다. 여기에서 구조는 구조에있는 서로 다른 데이터 항목의 최대 크기로 정렬됩니다.

    struct abc
   {
        int a;
        char b;
   };

여기서 구조 abc는 1 바이트 (char 멤버의 크기)보다 분명히 큰 int 멤버의 크기 인 4에 정렬됩니다 .

정렬

이 지정자는 structure, class 등과 같은 사용자 정의 유형을 2의 거듭 제곱 인 특정 값으로 정렬하는 데 사용됩니다.

정렬

이것은 구조 또는 클래스 유형이 정렬되는 값을 가져 오는 일종의 연산자입니다. 예 :

#include <iostream>
struct alignas(16) Bar
{
    int i; // 4 bytes
    int n; // 4 bytes
    short s; // 2 bytes
};
int main()
{
    std::cout << alignof(Bar) << std::endl; // output: 16
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.