C 객체의 메모리 레이아웃
질문:
C는 메모리에서 어떻게 배열되나요? 물체? 동적 캐스트는 오프셋을 사용하여 메모리에 있는 개체의 포인터만 조정하는 반면 재해석을 사용하면 이 포인터에 대해 모든 작업을 수행할 수 있다고 들었습니다. 나는 잘 이해하지 못한다. 세부정보를 제공해 주세요!
정답:
메모리 레이아웃
메모리 레이아웃은 주로 구현에 따라 다릅니다. 한 가지 중요한 예외가 있는데, 동일한 액세스 지정자를 가진 멤버 변수가 선언 순서대로 정렬된다는 것입니다.
§ 9.2.14 非静态数据成员(非联合)具有相同访问控制权的类(Clause 11)被分配,以便后续成员在类对象中具有更高的地址。具有不同访问控制权的非静态数据成员的分配顺序未指定(11)。实现对齐要求可能导致两个相邻成员不会立即相互分配;管理虚拟函数(10.3)和虚拟基类(10.1)的空间要求也可能导致这种情况。
기타 메모리 관리
클래스나 구조체는 멤버 변수 외에도 멤버 변수, 기본 클래스의 하위 객체, 가상 객체도 관리해야 합니다. 함수(예: 가상 테이블) 및 이 데이터의 패딩 및 정렬을 위해 제공되는 공간입니다. 구현에 따라 다르지만 Itanium ABI 사양이 널리 선택됩니다. gcc와 clang이 이를 따릅니다(적어도 어느 정도).
http://mentorembedded.github.io/cxx-abi/abi.html#layout
Itanium ABI
물론 Itanium ABI는 C 표준의 일부가 아니며 구속력도 없습니다. 자세한 내용은 구현자의 문서와 도구를 참조해야 합니다. clang은 클래스의 메모리 레이아웃을 볼 수 있는 도구를 제공합니다. 예를 들어 다음과 같습니다.
class VBase { virtual void corge(); int j; }; class SBase1 { virtual void grault(); int k; }; class SBase2 { virtual void grault(); int k; }; class SBase3 { void grault(); int k; }; class Class : public SBase1, SBase2, SBase3, virtual VBase { public: void bar(); virtual void baz(); // 不允许虚拟成员函数模板,原因考虑内存布局和虚表 // template<typename T> // virtual void quux(); private: int i; char c; public: float f; private: double d; public: short s; }; class Derived : public Class { virtual void qux(); }; int main() { return sizeof(Derived); }
클래스 메모리 레이아웃을 사용하는 소스 파일을 생성한 후 clang은 메모리 레이아웃을 표시합니다.
$ clang -cc1 -fdump-record-layouts layout.cpp
클래스 레이아웃:
*** Dumping AST Record Layout 0 | class Class 0 | class SBase1 (primary base) 0 | (SBase1 vtable pointer) 8 | int k 16 | class SBase2 (base) 16 | (SBase2 vtable pointer) 24 | int k 28 | class SBase3 (base) 28 | int k 32 | int i 36 | char c 40 | float f 48 | double d 56 | short s 64 | class VBase (virtual base) 64 | (VBase vtable pointer) 72 | int j | [sizeof=80, dsize=76, align=8 | nvsize=58, nvalign=8]
더 많은 메모리 레이아웃 정보
이 clang에 대한 추가 정보 이 기능은 Eli Bendersky의 블로그에서 찾을 수 있습니다:
http://eli.thegreenplace.net/2012/12/17/dumping-a-c-objects-memory-layout-with-clang/
gcc는 유사한 도구 `-fdump-class-hierarchy'를 제공합니다. 위에 제공된 클래스의 경우 다음을 출력합니다(무엇보다도):
Class Class size=80 align=8 base size=58 base align=8 Class (0x0x141f81280) 0 vptridx=0u vptr=((& Class::_ZTV5Class) + 24u) SBase1 (0x0x141f78840) 0 primary-for Class (0x0x141f81280) SBase2 (0x0x141f788a0) 16 vptr=((& Class::_ZTV5Class) + 56u) SBase3 (0x0x141f78900) 28 VBase (0x0x141f78960) 64 virtual vptridx=8u vbaseoffset=-24 vptr=((& Class::_ZTV5Class) + 88u)
멤버 변수를 항목화하지 않습니다(또는 적어도 변수를 얻는 방법을 모릅니다). 그러나 다음을 볼 수 있습니다. clang 레이아웃과 마찬가지로 오프셋 28과 64 사이에 위치해야 합니다.
기본 클래스가 Primary로 지정되어 있는 것을 확인할 수 있습니다. 이렇게 하면 클래스가 SBase1로 액세스될 때 이러한 포인터 조정이 필요하지 않습니다.
기타 컴파일러 지시어
다음과 동등한 지시어가 다른 컴파일러에 적용됩니다.
참조: https://blogs.msdn.microsoft.com/vcblog/2007/05/ 17/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022/
위 내용은 C는 메모리에서 객체를 어떻게 배열하며, 동적 캐스팅 및 재해석은 무엇을 의미합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!