查看编译器生成的默认函数?

Sou*_*uth 8 c++ visual-c++

有没有办法查看由编译器(如VC++ 2008)为未定义它们的类生成的默认函数(例如,默认复制构造函数,默认赋值运算符)?

Joh*_*itb 11

使用clang编译器,您可以通过传递-ast-dump参数来查看它们.Clang仍处于开发阶段,但您已经可以将它用于以下事情:

[js@HOST2 cpp]$ cat main1.cpp
struct A { };
[js@HOST2 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();
};
[js@HOST2 cpp]$
Run Code Online (Sandbox Code Playgroud)

我希望这就是你所要求的.让我们改变代码再看一遍.

[js@HOST2 cpp]$ cat main1.cpp
struct M { M(M&); };
struct A { M m; };
[js@HOST2 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();
};
[js@HOST2 cpp]$
Run Code Online (Sandbox Code Playgroud)

注意A现在隐式声明的复制构造函数如何具有非const引用参数,因为它的一个成员也具有(成员m),并且M没有声明默认构造函数.

要获取生成的代码,您可以让它发出虚拟机中间语言.让我们看一下生成的代码:

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

[js@HOST2 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
}
Run Code Online (Sandbox Code Playgroud)

现在,我不明白这种中间语言(在llvm.org中定义).但是您可以使用llvm编译器将所有代码转换为C:

[js@HOST2 cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | llc -march=c -o - | c++filt
[snippet]
void A::A()(struct l_struct.A *llvm_cbe_this) {
  *((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int )2u)]));
  return;
}


struct l_struct.A *A::operator=(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A
  *llvm_cbe_tmp__1) {
  unsigned int llvm_cbe_tmp3;

  llvm_cbe_tmp3 = *((&llvm_cbe_tmp__1->field1));
  *((&llvm_cbe_this->field1)) = llvm_cbe_tmp3;
  return llvm_cbe_this;
}


void A::A(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A *llvm_cbe_tmp__2) {
  unsigned int llvm_cbe_tmp3;

  llvm_cbe_tmp3 = *((&llvm_cbe_tmp__2->field1));
  *((&llvm_cbe_this->field1)) = llvm_cbe_tmp3;
  *((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int )2u)]));
  return;
}
Run Code Online (Sandbox Code Playgroud)

田田!注意它如何在复制构造函数和默认构造函数中设置虚拟表指针.希望这可以帮助.


小智 7

您可以使用调试器跟踪代码以查看正在进行的操作.例如:

#include <string>

struct A {
    int a[100];
    char c;
    std::string s;
};

int main() {
    A a;
    A b(a);
}
Run Code Online (Sandbox Code Playgroud)

在复制构造函数的'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) 
Run Code Online (Sandbox Code Playgroud)

最后一个是复制构造函数调用.如果您想了解更多细节,也可以追溯到这一点.

但是,如果您的问题是"如何查看复制构造函数的C++代码等",答案是您不能,因为没有 - 编译器生成汇编程序或机器代码(取决于您的编译器)对他们而言,不是C++代码.