c++ - 返回值 const 和 const 赋值——反汇编

标签 c++ disassembly

最近我一直在分析旧代码的某些部分,在某些情况下,从函数返回的值被分配给 const 变量,有时分配给 const&。出于好奇,我已经切换到 dissasembly 以查看差异。但在进入正题之前,让我画一个简单的例子来引用一些代码:

struct Data
{
    int chunk[1024];
};

Data getData()
{
    return Data();
}

int main()
{
    const std::string varInit{ "abc" }; // 1
    const std::string varVal = "abc"; // 2
    const std::string& varRef = "abc"; // 3

    const Data dataVal = getData(); // 4
    const Data& dataRef = getData(); // 5

    return 0;
}

上述代码的以下反汇编是使用禁用优化的 VS2015 获得的。

Disassembly for <code>(1)``(2)``(3)</code> 我不是 asm 专家,但乍一看我会说对于 (1)(2) 执行了类似的操作。尽管如此,令我惊讶的是,与 const& 在变量赋值期间未使用。

当数据按值从函数返回时,可以观察到同样的情况。 (5) 包含与(4) 相关的另外两个操作。 Disassembly for <code>(4)``(5)</code>

问题很窄:

  • 这些额外的操作从何而来,它们的目的是什么?一般不像这里:What's the purpose of the LEA instruction但在目前的情况下。
  • 这至少会影响底层数据大小可忽略不计的对象的性能吗? (与示例中使用的 Data 结构对比)
  • 启用优化后,这会有什么影响吗? (对于发布版本)

顺便说一句,我已经阅读了Why not always assign return values to const reference?关于在分配值时使用 const 和 const& 的优缺点,这可能有些相关但不是问题的一部分。

最佳答案

在情况 (3) 中,编译器在 [ebp-84] 处创建“隐藏”局部变量“std::string”让它命名为_84并像这样编写代码

const std::string _84 = "abc"; 
const std::string& varRef = _84;// lea + move (by sense varRef = &_84)

X& v - 通过意义和二进制代码与 X* v 相同- v实际上是指向 X 的指针在这两种情况下,只是使用了不同的语法

与情况(5)相同

const Data _20a0 = getData(); 
const Data& dataRef = _20a0; // by sense dataRef = &_20a0, but by syntax dataRef = _20a0

或者说如果你改为行

const Data& dataRef = getData();

写行

const Data& dataRef = dataVal;

您认为这一行恰好采用了 2 条 asm 指令:

lea eax,[dataVal]
mov [dataRef],eax

代码 (4,5) 和 Data getData()签名是绝对的噩梦,无话可说


为了更清楚 关于“按值”返回结构 - 函数只能返回寄存器作为结果(alaxeaxrax 在 x64 中)或 2 个寄存器 - edx:eax (8 字节,高位 edx)或 rdx:rax (x64 中为 16 字节)

万一 Data getData() - 不可能返回 Data原样。怎么?!?

所以实际上你的函数被转换为

Data* getData(Data* p)
{
    Data x;
    memcpy(p, &x, sizeof(Data));
    return p;
}

和代码

//const Data dataVal = getData(); 
Data _41A0, _3198, dataVal;
memcpy(&_3198, getData(&_41A0), sizeof(Data));
memcpy(&dataVal, &_3198, sizeof(Data));

//const Data& dataRef = getData(); 
Data _41A0, _3198, _20a0, &dataRef;
memcpy(&_51a8, getData(&_61b0), sizeof(Data));
memcpy(&_20a0, &_51a8, sizeof(Data));
dataRef = &_20a0;// very small influence compare all other

尝试计算编译器有多少无意义的 memcpy?

需要这样写代码

void InitData(Data* p);

Data dataVal;
InitData(&dataVal);

关于c++ - 返回值 const 和 const 赋值——反汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41070592/

相关文章:

c++ - 自定义内存分配和删除

c++ - C++ 中的 Random() 效率

C++ 宏从 .cpp 初始化在 .h 中声明的变量

gdb - 如何用 GDB 分解内存范围?

assembly - 您可以在反汇编程序(例如 dbg)中删除和添加指令吗?

c# - 如何在 C# 中从 IFileDialogCustomize GetEditBoxText() 获取字符串

c++ - 我的cout怎么了?

assembly - 如何将shellcode分解为汇编指令? [复制]

c - GDB - 显示地址

c - 了解汇编代码中的减法和乘法