C++ 在ARM体系结构中,C函数如何返回大于一个字的值

C++ 在ARM体系结构中,C函数如何返回大于一个字的值,c++,c,arm,C++,C,Arm,在C程序中,内存布局由.BSS、.DATA、.TEXT、堆和堆栈组成。当一个函数返回的值小于一个字时,它将进入R0寄存器,但如果返回值大于一个字,它将通过内存返回。例如: LargeType t; t = func(arg); 其实施方式如下: LargeType t; (void) func(&t,arg); 我的问题是编译器使用哪部分内存来超过“t”?调用func(&t,arg)将继续并用所需的值填充t的内存地址。因此t必须在调用方函数的堆栈上分配(除非您想动态分配t,如t=ma

在C程序中,内存布局由.BSS、.DATA、.TEXT、堆和堆栈组成。当一个函数返回的值小于一个字时,它将进入R0寄存器,但如果返回值大于一个字,它将通过内存返回。例如:

LargeType t;
t = func(arg);
其实施方式如下:

LargeType t;
(void) func(&t,arg);
我的问题是编译器使用哪部分内存来超过“t”?

调用func(&t,arg)将继续并用所需的值填充t的内存地址。因此t必须在调用方函数的堆栈上分配(除非您想动态分配t,如t=malloc(sizeof(LargeType)),它将在堆上)。不确定编译器在这里要做什么

/* Caller function */
...
LargeType t;     /* Allocated on caller's stack */
LargeType *t = malloc(sizeof(LargeType));    /* Allocation on heap */
(void) func(&t, arg);    /* Fills up t with required value */

除异常外,基本上使用了In + C++ ABI。在这种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;

“当一个函数返回的值小于一个字时,它将进入R1寄存器”你的意思是
r0
?你基本上没有回答你自己的问题,因为它被实现为
func(&t,arg)-在这种情况下,调用者管理内存并只传入指向该内存的指针-即,它与函数的任何其他参数一样。但是,如果代码是C++,而不是C,那么它的代码分配的复杂程度就更高了。