函数如何实际返回 C 中的结构变量? [英] How does function ACTUALLY return struct variable in C?

查看:28
本文介绍了函数如何实际返回 C 中的结构变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很清楚函数的返回值如何,只是开始:

int f(){int a = 2;返回一个;}

现在 a 获取堆栈中的内存,其生命周期在 f() 内,以便返回值,它将值复制到一个特殊的寄存器中被调用者读取,因为它知道被调用者已经为他放置了值.(由于返回值持有者特殊寄存器大小的大小是有限的,这就是为什么我们不能返回大对象,因此在高级语言的情况下,当我们想要返回对象函数实际上将堆中的对象地址复制到该特殊寄存器)

当我想返回一个结构变量而不是指针时,让我们回到 C 语言:

结构清单{字符名称[20];整数;};结构库存功能();int main(){结构库存项目;项目=功能();printf("\nam in main\n");printf("\n%s\t",items.name);printf(" %d\t",items.number);获取();返回0;}结构库存功能(){结构库存项目;printf(" 请输入项目名称\n ");scanf(" %s ",&items.name );printf(" 请输入项目数\n ");scanf("%d",&items.number);退换货品;}

代码派生自:https://stackoverflow.com/a/22952975/962545

这是交易,

让我们从 main 开始,items 变量声明但未初始化,然后调用返回初始化结构变量的函数,该变量被复制到 main 中的变量.现在我有点不清楚 function() 如何返回结构变量 items 不是动态创建的(技术上不在堆中)所以这个变量的生命周期在 function() 主体,变量 item 的大小也可能足够大,无法放入特殊寄存器,那么为什么它有效?(我知道我们可以在函数内部动态分配 item 和返回地址但我不想替代,我正在寻找解释)

问题:虽然 它可以工作,但是 function() 实际上如何返回结构变量和当它应该随着 function() 返回而死亡时,被复制到 main 中的 items 变量.

我肯定遗漏了重要的东西,详细的解释会有所帮助.:)

其他答案参考:

  1. https://stackoverflow.com/a/2155742/962545
  2. 命名为返回值优化

解决方案

详细信息因调用约定而异.一些 ABI 没有传递整个结构的调用约定,在这种情况下,编译器可以自由地做任何它认为有意义的事情.

示例包括:

  • 将整个结构作为一系列连续的寄存器传递和返回(通常与小"结构一起使用)
  • 将整个结构作为参数块放在堆栈上
  • 分配一个足够大的空参数来容纳结构体,并用返回值填充
  • 将结构体的(堆栈)地址作为参数传递(就像函数被声明一样void function(struct inventory *))

这些实现中的任何一个都可以符合此处的 C 规范.但是,让我们看一个具体的实现:我的 GCC ARM 交叉编译器的输出.

编译你给的代码给了我这个:

主要:stmfd sp!, {fp, lr}添加 fp, sp, #4子 sp, sp, #48子 r3, fp, #52移动 r0, r3bl函数(PLT)

目标操作数总是在左边.可以看到程序预留了栈空间,然后将栈空间的地址作为r0(ARM EABI调用约定中的第一个参数)传递.function 没有参数,所以这个参数显然是我们编译器添加的人工参数.

function 看起来像这样:

功能:stmfd sp!, {r4, fp, lr}添加 fp、sp、#8子 sp, sp, #36str r0, [fp, #-40]ldr r3, .L6...添加 r2, pc, r2移动 r0, r2移动 r1, r3bl scanf(PLT)ldr r3, [fp, #-40]mov ip, r3子 r4, fp, #36ldmia r4!, {r0, r1, r2, r3}stmia ip!, {r0, r1, r2, r3}ldmia r4, {r0, r1}stmia ip, {r0, r1}ldr r0, [fp, #-40]sub sp, fp, #8ldmfd sp!, {r4, fp, pc}

这段代码基本上将单个参数存储在 [fp, #-40] 中,然后加载它并在它指向的地址开始存储数据.最后,它再次返回 r0 中的这个指针值.实际上,编译器已经将函数签名变成了

struct inventory *function(struct inventory *)

其中返回的结构体由调用者在栈上分配,传入,然后返回.

How does a function return value is clear to me, just to kick start:

int f()
{
  int a = 2;
  return a;
}

Now a gets the memory in stack and its life-span is within the f() in order to return the value it copies the value to a special register which is read by the caller as it knows that the callee have placed the value for him. (Since the size of return-value-holder special register size is limited that's why we cant return large objects therefore In case of advance languages when we want to return object function actually copies the address of object in heap to that special register)

Lets come back to C for a situation when i want to return a struct variable not pointer:

struct inventory
{
    char name[20];
    int number;
};
struct inventory function();

int main()
{
    struct inventory items;
    items=function();
    printf("\nam in main\n");
    printf("\n%s\t",items.name);
    printf(" %d\t",items.number); 
    getch();
    return 0;
}

struct inventory function()
{
    struct inventory items;
    printf(" enter the item name\n ");
    scanf(" %s ",&items.name );
    printf(" enter the number of items\n ");
    scanf("%d",&items.number );
    return items;
}

Code forked from: https://stackoverflow.com/a/22952975/962545

Here is the deal,

Lets start with main, items variable declared but not initialized and then function is called which return initialized structure variable which gets copied to the one in main. Now I am bit blurred to understand how function() returned struct variable items which is not dynamically created(technically not in heap) so this variable's life-span is within the function() body, also size of variable item can be huge enough not to fit in special register so why it worked?.(I know we can dynamically allocate item inside function and return the address but I don't want alternative, I am looking for explanation)

Question: Although it works but how does function() actually returned the struct variable and get copied to items variable in main when it is supposed to die with function() return.

I am surely missing important thing, detailed explanation would help. :)

EDIT: Other Answer References:

  1. https://stackoverflow.com/a/2155742/962545
  2. Named as return value optimization

解决方案

Details vary widely by calling convention. Some ABIs have no calling convention for passing whole structures, in which case the compiler is free to do whatever it thinks makes sense.

Examples include:

  • Passing and returning the entire struct as a series of consecutive registers (often used with "small" structs)
  • Placing the entire struct as an argument block on the stack
  • Allocating an empty argument big enough to hold the struct, to be filled with a return value
  • Passing the (stack) address of the struct as an argument (as if the function was declared void function(struct inventory *))

Any of these implementations could conform to the C spec here. But, let's look at a specific implementation: the output from my GCC ARM cross-compiler.

Compiling the code you gave gives me this:

main:
    stmfd   sp!, {fp, lr}
    add fp, sp, #4
    sub sp, sp, #48
    sub r3, fp, #52
    mov r0, r3
    bl  function(PLT)

Destination operands are always on the left. You can see that the program reserves stack space, then passes the address of the stack space as r0 (the first argument in the ARM EABI calling convention). function takes no arguments, so this argument is clearly an artificial argument added by our compiler.

function looks like this:

function:
    stmfd   sp!, {r4, fp, lr}
    add fp, sp, #8
    sub sp, sp, #36
    str r0, [fp, #-40]
    ldr r3, .L6

        ...
    add r2, pc, r2
    mov r0, r2
    mov r1, r3
    bl  scanf(PLT)
    ldr r3, [fp, #-40]
    mov ip, r3
    sub r4, fp, #36
    ldmia   r4!, {r0, r1, r2, r3}
    stmia   ip!, {r0, r1, r2, r3}
    ldmia   r4, {r0, r1}
    stmia   ip, {r0, r1}
    ldr r0, [fp, #-40]
    sub sp, fp, #8
    ldmfd   sp!, {r4, fp, pc}

This code basically stashes the single argument in [fp, #-40], then later loads it and begins stashing data at the address it points to. At the end, it returns this pointer value in r0 again. Effectively, the compiler has made the function signature into

struct inventory *function(struct inventory *)

where the returned structure is allocated on the stack by the caller, passed in, and then returned.

这篇关于函数如何实际返回 C 中的结构变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆