在C程序中,内存布局由.BSS、.DATA、.TEXT、HEAP和STACK组成。当函数返回值小于一个字时,它会转到R0寄存器,但如果返回值大于一个字,它会通过内存返回。例如:
LargeType t;
t = func(arg);
实现为:
LargeType t;
(void) func(&t,arg);
我的问题是编译器使用内存的哪一部分来过去“t”?
最佳答案
ARM C++ ABI本质上使用 Itanium C++ ABI(异常(exception)情况除外)。在该 ABI 中,按值返回大对象的调用约定是调用者传递一个隐藏指针,并且函数使用该指针在 return 语句中创建对象。这就是返回值优化的实现方式。
现在,您提供的翻译不正确。您开始使用的代码使用赋值而不是初始化:
LargeType t;
t = func(arg);
编译器完成的翻译将相当于:
LargeType t;
LargeType __tmp;
func(&__tmp,arg);
t.operator=(__tmp);
__tmp.~LargeType();
临时变量将在堆栈中创建,地址传递给将使用它来创建对象的函数。然后将发生赋值,并且在完整表达式 t = func(arg);
的末尾,临时变量将被销毁。
将其与初始化情况进行比较:
LargeType t = func(arg);
在这种情况下,编译器可以执行您提到的转换,翻译后的代码将是:
LargeType t;
func(&t,arg);
非常重要的区别是初始化和赋值是完全不同的操作。在初始化的情况下,对象变成,什么都没有,现在有一些东西。在赋值的情况下,对象已经曾经,它有一个状态,并且它可能正在管理资源。如果允许您建议的转换,则此代码将泄漏内存:
struct Test {
int *p; // assume other members make this object large
Test() : p(new int()) {}
Test(int i) : p(new int) { *p = i; }
Test(Test const & other) : p(new int) { *p = other->p; }
~Test() { delete p; }
Test& operator=(Test const & other) { *p = other->p; }
};
Test f(int arg) {
return Test(1)
}
Test t;
t = f(5);
转换后的代码会泄漏的地方:
Test t; // allocates a pointer
f(&t, 5); // expands to:
// __ret->p = new int; // leak!
// *(__ret->p) = 5;
关于c++ - ARM架构中C函数如何返回大小超过一个字的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20225586/