函数返回结构体,则编译器会为返回值做一次寄存器的来回拷贝,是多余动作吗?解决思路
函数返回结构体,则编译器会为返回值做一次寄存器的来回拷贝,是多余动作吗?
x86结构下的C++编译器例如VC,如果返回的是基本类型,那么就caller结束直接放到eax里面,caller从eax里面拿到返回值,放入一个堆栈变量。
但是我发现,如果返回的是一个结构体(哪怕是只有一个int的结构体)返回的行为会不一样。例如:
那么foo在返回前就把ret放到eax里面: mov eax, DWORD PTR _ret$[ebp]
在main函数里面call了foo之后: mov DWORD PTR _iret$[ebp], eax,把eax的值放入iret局部变量。
这理解起来都没有问题。但是我稍微改了一下代码:
foo函数在返回值钱也是把s1中的一个值放入eax: mov eax, DWORD PTR _s1$[ebp]
但是main函数的行为发生了变化,在call函数foo之后,代码变成了:
00036 e8 00 00 00 00 call ?foo@@YA?AUs@@XZ ; foo
0003b 89 45 f8 mov DWORD PTR $T2556[ebp], eax ; 从eax到内存
0003e 8b 45 f8 mov eax, DWORD PTR $T2556[ebp] ; 再从内存在eax
00041 89 45 fc mov DWORD PTR _s2$[ebp], eax
我不知道先把eax的值mov到DWORD PTR $T2556[ebp],在下面一句话mov回eax,这样做有什么意义?
直接第三句话mov DWORD PTR _s2$[ebp], eax不就解决问题了么?
------解决方案--------------------
这是没有优化的代码 完全按照源码指定的行为进行操作 你把优化打开肯定大不一样
------解决方案--------------------
第一,编译器的优化程度视编译器而定,不由C++标准强制规定
第二,C++中的结构体本质上是默认public权限的类,而类有构造析构复制函数等,优化时肯定要考虑这些,不能像基础数据类型一样直接复制——哪怕是一个只有int成员的结构体,起码也有自己的this指针这个隐藏变量。
x86结构下的C++编译器例如VC,如果返回的是基本类型,那么就caller结束直接放到eax里面,caller从eax里面拿到返回值,放入一个堆栈变量。
但是我发现,如果返回的是一个结构体(哪怕是只有一个int的结构体)返回的行为会不一样。例如:
- C/C++ code
int foo(){ int ret=44; return ret; }; int main( void){ int iret=foo(); return 0; }
那么foo在返回前就把ret放到eax里面: mov eax, DWORD PTR _ret$[ebp]
在main函数里面call了foo之后: mov DWORD PTR _iret$[ebp], eax,把eax的值放入iret局部变量。
这理解起来都没有问题。但是我稍微改了一下代码:
- C/C++ code
struct s{ int a; }; s foo(){ s s1={44}; return s1; }; int main( void){ s s2=foo(); return 0; }
foo函数在返回值钱也是把s1中的一个值放入eax: mov eax, DWORD PTR _s1$[ebp]
但是main函数的行为发生了变化,在call函数foo之后,代码变成了:
00036 e8 00 00 00 00 call ?foo@@YA?AUs@@XZ ; foo
0003b 89 45 f8 mov DWORD PTR $T2556[ebp], eax ; 从eax到内存
0003e 8b 45 f8 mov eax, DWORD PTR $T2556[ebp] ; 再从内存在eax
00041 89 45 fc mov DWORD PTR _s2$[ebp], eax
我不知道先把eax的值mov到DWORD PTR $T2556[ebp],在下面一句话mov回eax,这样做有什么意义?
直接第三句话mov DWORD PTR _s2$[ebp], eax不就解决问题了么?
------解决方案--------------------
这是没有优化的代码 完全按照源码指定的行为进行操作 你把优化打开肯定大不一样
------解决方案--------------------
第一,编译器的优化程度视编译器而定,不由C++标准强制规定
第二,C++中的结构体本质上是默认public权限的类,而类有构造析构复制函数等,优化时肯定要考虑这些,不能像基础数据类型一样直接复制——哪怕是一个只有int成员的结构体,起码也有自己的this指针这个隐藏变量。