当前位置: 首页 > 知识库问答 >
问题:

简单构造函数的复杂编译器输出

易扬
2023-03-14

我有一个带有两个64位整数成员的结构X,以及一个构造函数

struct X
{
    X(uint64_t a, uint64_t b)
    {
        a_ = a; b_ = b;
    }

    uint64_t a_, b_;
};
X::X(unsigned long, unsigned long):
    push    rbp
    mov     rbp, rsp
    mov     QWORD PTR [rbp-8], rdi
    mov     QWORD PTR [rbp-16], rsi
    mov     QWORD PTR [rbp-24], rdx
    mov     rax, QWORD PTR [rbp-8]
    mov     QWORD PTR [rax], 0
    mov     rax, QWORD PTR [rbp-8]
    mov     QWORD PTR [rax+8], 0
    mov     rax, QWORD PTR [rbp-8]
    mov     rdx, QWORD PTR [rbp-16]
    mov     QWORD PTR [rax+8], rdx
    mov     rax, QWORD PTR [rbp-8]
    mov     rdx, QWORD PTR [rbp-24]
    mov     QWORD PTR [rax], rdx
    nop
    pop     rbp
    ret
X::X(unsigned long, unsigned long):
    push    rbp
    mov     rbp, rsp
    mov     qword ptr [rbp - 8], rdi
    mov     qword ptr [rbp - 16], rsi
    mov     qword ptr [rbp - 24], rdx
    mov     rdx, qword ptr [rbp - 8]
    mov     qword ptr [rdx], 0
    mov     qword ptr [rdx + 8], 0
    mov     rsi, qword ptr [rbp - 16]
    mov     qword ptr [rdx + 8], rsi
    mov     rsi, qword ptr [rbp - 24]
    mov     qword ptr [rdx], rsi
    pop     rbp
    ret

共有1个答案

上官凯泽
2023-03-14

未经优化的代码总是将所有C++变量(包括函数arg)存储到语句之间的内存位置,以便调试器可以读取甚至修改这些值。(因为它没有花费任何时间进行寄存器分配。)这包括在函数的第一个C++语句之前将寄存器ARG存储到内存中。

这是Intel-syntax程序集,类似于fromgcc-masm=intel,所以它使用的是目的地、源顺序。(我们可以根据使用PTR、方括号和寄存器名中缺少%来判断。)

前3个存储是函数参数(this,a,b),这些参数按照x86-64 System V ABI的调用约定传递到寄存器RDI、RSI和RDX中。

mov     QWORD PTR [rbp-8], rdi        # this
mov     QWORD PTR [rbp-16], rsi       # a
mov     QWORD PTR [rbp-24], rdx       # b
mov     rax, QWORD PTR [rbp-8]
mov     QWORD PTR [rax], 0           # this->a_ = 0
mov     rax, QWORD PTR [rbp-8]
mov     QWORD PTR [rax+8], 0         # this->b_ = 0

等等,实际上必须先写到b_,然后写到a_,因为需要结构来匹配声明和内存顺序。因此[rax+8]必须是b_,而不是a_

mov     rax, QWORD PTR [rbp-8]
mov     rdx, QWORD PTR [rbp-16]        # reload a
mov     QWORD PTR [rax+8], rdx         # this->b_ = a
mov     rax, QWORD PTR [rbp-8]
mov     rdx, QWORD PTR [rbp-24]        # reload b
mov     QWORD PTR [rax], rdx           # this->a_ = b

因此您的asm与您的问题中的C++源代码不匹配。

 类似资料:
  • 今天我遇到了一些我不太理解的复制构造函数。 考虑下一个代码: 然后在将原点分配给复制时调用复制构造函数,这是有意义的。但是,如果我将复制的声明更改为 它不叫。即使当我使用< code>create()函数时,它也不会调用复制构造函数。但是,当将其更改为 它确实调用了复制构造函数。一些研究解释说,允许编译器优化复制构造函数,这听起来是件好事。直到复制构造函数是非默认的,因为那时它可能会,也可能不会做

  • 以下代码使用Clang(3.9.1测试)和GCC(6.3测试)编译,如此链接所示:https://godbolt.org/g/kO1nBa.但是,MSVC(19.00.24215.1测试)无法编译它: 错误C2131:表达式未计算为常量 注意:失败是由赋值操作的计算引起的 注意:在评估'ExtraResidentsValueWitnessTable::ExtraResidentsValueWitn

  • 主要内容:默认拷贝构造函数拷贝和复制是一个意思,对应的英文单词都是 。 对于计算机来说,拷贝是指用一份原有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。 在 C++ 中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对

  • 该程序应该提示用户输入日期,它会自行递增。我遇到了DateTest类的问题。错误消息说“无法在数组类型Date[]上调用nextDay()” 已更新 我删除了不必要的语句。但是现在我收到了这个错误消息, 错误:在类Date中找不到Main方法,请将Main方法定义为:public static void Main(String[]args) 我必须把主要方法移动到任何地方吗?

  • 问题内容: 当我写课时 编译器生成的构造函数是 public 还是 default ? 公众会喜欢 而默认类似于 问题答案: 这取决于您的 类可见性* 。编译器使用类可见性并生成具有 相同可见性 的无参数默认构造函数 *

  • 我使用的是C(Qt)。 我正在扩展一个单例类,而一个子类只有静态方法。我没有创建子类的任何实例。Singleton类的构造函数和析构函数都是私有的,所以我不能访问它的构造函数和析构函数。 我使用子类::getInstance()调用父类的getInstance()。我只使用子类的静态方法(因此不需要实例化子类)。 所以我的问题是,我在编译时收到警告- "子类:由于基类析构函数不可访问,无法生成析构