2010-01-24 2 views
8

VC++ 2008과 같은 컴파일러가 정의하지 않은 클래스에 대해 생성 된 기본 함수 (예 : 기본 복사 생성자, 기본 할당 연산자)를 볼 수있는 방법이 있습니까?컴파일러에서 생성 된 기본 함수를 볼 수 있습니까?

+1

귀하의 질문에 대한 혼란이있는 것 같습니다 :

class X: public Base { int* a; double b; Y c; }; 

그런 다음 컴파일러는 다음의 등가를 생성합니다. 함수 프로토 타입을 어떻게보아야하는지, 어떤 것이 기본값으로 구현되었는지, 어떤 코드가 구현되었는지, 기본 구현을위한 코드를 어떻게 볼 수 있습니까? –

답변

11

clang 컴파일러를 사용하면 -ast-dump 인수를 전달하여 볼 수 있습니다. Clang은 아직 개발 단계에 있지만 다음 작업을 위해 이미 사용할 수 있습니다.

[[email protected] cpp]$ cat main1.cpp 
struct A { }; 
[[email protected] cpp]$ clang++ -cc1 -ast-dump main1.cpp 
typedef char *__builtin_va_list; 
struct A { 
public: 
    struct A; 
    inline A(); 
    inline A(struct A const &); 
    inline struct A &operator=(struct A const &); 
    inline void ~A(); 
}; 
[[email protected] cpp]$ 

희망 사항입니다. 코드를 변경하고 다시 살펴 봅시다. 회원 중 하나가 너무 있기 때문에 A의 암시 적으로 선언 복사 생성자는 이제, const가 아닌 참조 매개 변수를 얼마나

[[email protected] cpp]$ cat main1.cpp 
struct M { M(M&); }; 
struct A { M m; }; 
[[email protected] cpp]$ clang++ -cc1 -ast-dump main1.cpp 
typedef char *__builtin_va_list; 
struct M { 
public: 
    struct M; 
    M(struct M &); 
    inline struct M &operator=(struct M const &); 
    inline void ~M(); 
}; 
struct A { 
public: 
    struct A; 
    struct M m; 
    inline A(); 
    inline A(struct A &); 
    inline struct A &operator=(struct A const &); 
    inline void ~A(); 
}; 
[[email protected] cpp]$ 

공지 사항 (회원 m), 및 M 선언에는 기본 생성자가 없다.

생성 된 코드를 가져 오기 위해 가상 컴퓨터 중간 언어를 내보낼 수 있습니다. 의는이를 위해 생성 된 코드를 살펴 보자 :

struct A { virtual void f(); int a; }; 
A f() { A a; a = A(); return a; } // using def-ctor, assignment and copy-ctor 

[[email protected] cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | c++filt 
[ snippet ] 
define linkonce_odr void @A::A()(%struct.A* nocapture %this) nounwind align 2 { 
entry: 
    %0 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1] 
    store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %0 
    ret void 
} 

define linkonce_odr %struct.A* @A::operator=(A const&)(%struct.A* %this, 
    %struct.A* nocapture) nounwind align 2 { 
entry: 
    %tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp3 = load i32* %tmp2       ; <i32> [#uses=1] 
    store i32 %tmp3, i32* %tmp 
    ret %struct.A* %this 
} 

define linkonce_odr void @A::A(A const&)(%struct.A* nocapture %this, %struct.A* nocapture) 
    nounwind align 2 { 
entry: 
    %tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1] 
    %tmp3 = load i32* %tmp2       ; <i32> [#uses=1] 
    store i32 %tmp3, i32* %tmp 
    %1 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1] 
    store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %1 
    ret void 
} 

지금, 내가 (llvm.org에 정의 된) 그 중간 언어를 이해하지 않습니다. 그러나 llvm 컴파일러를 사용하여 해당 코드를 모두 C로 변환 할 수 있습니다.

타다! Copy 생성자와 기본 생성자에 가상 테이블 포인터를 설정하는 방법에 유의하십시오. 희망이 도움이됩니다.

+0

Windows 7에서 Clang을 실행할 수 있습니까? MS 윈도우 용 다운로드를 찾을 수 없습니다. – Southsouth

+0

왜 "구조체 A;" 다음에 생성 된 코드의 일부입니다. struct A { public: struct A; inline A(); ... } Southsouth

0

개체보기 도구 (예 : objdump 또는 dumpbin)는 출력 개체 파일을 디스 어셈블 할 수 있습니다. 그런 다음 주위를 두드려보고 관심있는 함수/메소드에 대해 어떤 지침이 생성되는지 확인할 수 있습니다.

7

디버거로 코드를 추적하여 무슨 일이 일어나고 있는지 확인할 수 있습니다. 예 :

복사 생성자가 'b'구성시 중단 점을 설정합니다. VC++ 6 디버거의 해당 지점에서 어셈블러 출력은 다음과 같습니다.

12:  A b(a); 
00401195 lea   eax,[ebp-1B0h] 
0040119B push  eax 
0040119C lea   ecx,[ebp-354h] 
004011A2 call  @ILT+140(A::A) (00401091) 

마지막은 복사 생성자 호출입니다. 자세한 내용을 원한다면 그 내용을 추적 할 수 있습니다.

그러나 질문이 "어떻게 복사 생성자 외의 C++ 코드를 볼 수 있습니까?"라는 대답이 없기 때문에 대답이 없습니다. 컴파일러는 어셈블러 또는 기계 코드를 생성합니다 귀하의 컴파일러)에 대한 C + + 코드가 아닙니다.

-1

이 기능을 볼 필요가 있습니까?

기본적으로 컴파일러는 각 멤버 변수에 대해 복사 생성자 또는 할당 연산자를 호출하여 컴파일러를 만듭니다.

데이터를 관리하기 위해 참조 카운팅을 사용하는 객체를 사용할 때 기본 복사 생성자는 객체의 사본을 만들지 만 객체가 가리키는 데이터의 복사본은 만들지 않습니다. 포인터에 대해서도 마찬가지입니다.따라서 다음과 같은 클래스가있는 경우 :

class aClass 
{ 
    int one; 
    int *ptwo; 
}; 

기본 복사 생성자는 데이터 a와 포인터 b 만 복사합니다. 그러나 그는 b가 가리키는 데이터를 복사하지 않습니다. 이 클래스 포인터 대신 ptwo의 값을 복사 할 경우

aClass a, b; 
a.ptwo = new int; 
a.one = 1; 
*(a.ptwo) = 2; 

b = a; 

*(b.ptwo) = 1; 
//a.ptwo now points to an integer with the value of 1 

처럼이 클래스를 사용하는 경우 당신은 당신의 자신의 복사 할당 연산자의 기능을해야합니다. 기본 함수가하는 일에 대해 더 자세히 알고 싶다면 "효과적인 C++"책을 살펴보십시오.
클래스의 기본 기능, 수행하지 않는 기능, 수행해야 할 기능, 직접 작성하는 기능 등을 설명하는 전체 장을 제공합니다. 이 기능에 대해 알고 싶다면 웹에서 디지털 버전을 다운로드 할 수 있습니다.

2

컴파일러에서 생성 한 메서드는 소스 코드에 존재하지 않는 추상 메서드입니다.
아래 예제를 보면 컴파일러에서 생성 된 네 가지 메소드가 소스 코드 수준에서 수행해야하는 작업을 설명하려고합니다. 이것에서 정상적인 클래스를 외삽 할 수 있어야합니다. 이 같은 클래스가있는 경우

는 :

X::X() // Default constructor 
    :Base() Calls the base class default constructor 
    //,a pointers are POD no default initialization 
    //,b double are POD no default initialization 
    ,c() //Call default constructor on each non POD member 
{} 

X::~X() // Default destructor 
{} 
// Destructor for each non POD member in reverse order 
~c()  calls the destructor of the class type 
//~b  double are POD no destructor 
//~a  pointers are POD no destructor 
~Base() // Calls the base class destructor 

X::X(X const& copy) 
    :Base(copy) // calls the base class copy constructor 
    // Copies each member using its copy constructor 
    ,a(copy.a)  // Pointers copied (Note just the pointer is copied, not what it points at) 
    ,b(copy.b)  // Double copied. 
    ,c(copy.c)  // Uses copy constructor of the class type (must be accessible) 
{} 

X& X::operator=(X const& copy) 
{ 
    Base::operator=(copy); // Calls the base class assignment operator 
    // Copies each member using the members assignment operator 
    a = copy.a; // Pointers copied (Note just the pointer is copied, not what it points at) 
    b = copy.b; // Double copied 
    c = copy.c; // Uses assignment operator of the class type (must be accessible) 

    return *this; 
} 
+0

참조 : http://stackoverflow.com/a/1810320/14065 –

관련 문제