C++ 에서 변수,구조체,클래스 등의 변수,맴버변수 선언 경계를 맞추기 위해서 __declspec(align(N)) / alignas(N) 을 사용할 수 있습니다. 지금은 C++ 의 표준인 alignas(N) 만을 권장 사용하고 있습니다.
메모리 경계란 해당 변수,객체 메모리의 선언 지점 (시작위치) 를 원하는 위치로 맞추겠다는 의미 입니다. 이런작업을 하는 이유는 캐시라인을 맞추거나 특별한 경계에 맞춰져야만 하는 함수 (interlocked ….128 ) 사용시 필요합니다.
Visual C++ 컴파일러의 경우 지역변수의 대상으로는 alignas 키워드가 작동되지 못했습니다. 왜냐면 지역변수라는 것은 ebp,rbp 또는 esp,rsp 기준으로 스택 메모리에 변수를 쌓아 올리는 방식이기 때문입니다. 애초에 ebp,rbp 가 원하는 경계로 만들어지지 않았다면 그 뒤의 경계로 맞출 수가 없기 때문입니다.
함수 호출자가 esp,rsp 를 경계에 맞춰주지 않았다면, 피호출자 입장에서는 esp, rsp 가 얼마의 경계에 맞추어져 있는지 살펴보지 않았기 때문이죠.
Visual C++ 에서도 역시 같은 상황이었으며, 이렇게 되면 실제로 alignas 가 재 역할을 못하게 됩니다.
64bit 환경에서는 스택의 메모리와 동적할당 malloc 의 메모리는 16byte 경계를 맞춰줌은 보장하기 때문에 align(16) 까지는 가능하지만 그 이상인 align(32), align(64) … 은 현실적으로 불가능한 (하지못하는) 상황 이었습니다.
프로카데미 수업시간에도 항상 이에대한 테스트를 해보이며 작동되는 경우와 작동이 되지 않는 사례들을 안내하며 진행을 하였습니다. 구조체의 맴버 변수나, 그외 변수들은 모두 선언입장의 시작위치를 0 이라는 기준으로 잡아서 경계를 맞출 뿐, 시작점이 맞지 않았다면 이후의 모든 변수들이 틀어지기 때문입니다.
그런데 어느날… 수업시간에 설명중 갑작스럽게 결과가 바뀌었습니다. 3개월 전만해도 되지 않던것이 되던것이죠 !!? (3개월 마다 같은 수업이 진행 됩니다) 테스트를 해보는데 지역변수에 선언되는 alignas(64), alignas(128) 가 너무나 정확하게 맞춰지는 것이 확인 되었습니다. 분명히 지난 3개월 전에는 안되던것이?
그래서 Visual Studio 릴리즈노트와 마이크로소프트 문서들을 살펴보니 다음과 같은 내용을 확인 하였습니다.
Visual Studio 2019 버전 16.4 릴리스 정보
https://docs.microsoft.com/ko-kr/visualstudio/releases/2019/release-notes-v16.4#16.4.0
…
2019년 12월 3일 — Visual Studio 2019 버전 16.4.0
= 구조적 바인딩의 alignas(C++17)가 작동에 대한 패치
마이크로소프트 개발자 포럼에 alignas 키워드에 대한 미작동 건이 올라오고, 2019년 12월 3일 업데이트에 이 부분이 반영 되었습니다.
alignas(64) 가 들어간 변수,객체 지역변수 선언시 해당 함수의 스택확보 부분에 아래의 코드가 삽입됩니다.
and esp,0FFFFFFC0h
esp 를 0xffffffc0 으로 마스킹하여 하위 6 bit 를 날려서 63 이하의 수치를 지워버립니다. 이로서 esp 는 64 경계에 맞춰진 상태로 작아져서 스택을 확보하게 됩니다.
이제는 malloc 의 경우는 어쩔 수 없이 align_malloc 을 사용해야 하지만, 지역변수의 경우는 alignas 를 믿고 사용하여도 되게 되었습니다. 물론 이는 VC 버전에 따라 다를 수 있습니다. 사용중인 컴파일러는 어떻게 결과를 뽑아주는지 꼭 어셈블리 확인 후 진행이 되어야 하겠습니다.
안되는것이 당연한줄 알고 조심해서 사용합시다! 라는 수업을 진행 해왔었는데 이게 버그였을 줄은…






