简体   繁体   English

变量返回还是直接返回?

[英]Variable to return or return directly?

I'm learning to program and sometimes I find that using a variable to return makes my code more readable.我正在学习编程,有时我发现使用变量返回使我的代码更具可读性。

I was wondering if these functions perform the same operations and are equally efficient.我想知道这些函数是否执行相同的操作并且同样有效。

CASE 1:情况1:

int Foo1()
{
    int x = 5 + 6 + 7;      // Return variable
    return x;
}

int Foo2(int y)
{
    return 5 + 6 + 7;
}

In this case I think that the initialization and sum occur at compile time so there's no difference between them.在这种情况下,我认为初始化和求和发生在编译时,因此它们之间没有区别。

CASE 2:案例2:

int Foo1(int y)
{
    int x = y + 6 + 7;      // Return variable
    return x;
}

int Foo2(int y)
{
    return y + 6 + 7;
}

But, what happen in this case?但是,在这种情况下会发生什么? It seems that the initialization occur at execution time and it has to perform it.似乎初始化发生在执行时,它必须执行它。

Is returning the value directly faster than initialize a variable and then returning it?直接返回值是否比初始化变量然后返回它更快? Should I always try to return values directly instead using a variable to return?我应该总是尝试直接返回值而不是使用变量返回吗?

You can easily try this yourself.您可以轻松地自己尝试。
You can get the assembly from your compiler您可以从编译器中获取程序集

Without optimization:无优化:
( gcc -S -O0 -o src.S src.c ) ( gcc -S -O0 -o src.S src.c )

    .file   "so_temp.c"
    .text
    .globl  case1Foo1
    .type   case1Foo1, @function
case1Foo1:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $18, -4(%rbp)
    movl    -4(%rbp), %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   case1Foo1, .-case1Foo1
    .globl  case1Foo2
    .type   case1Foo2, @function
case1Foo2:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $18, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   case1Foo2, .-case1Foo2
    .globl  case2Foo1
    .type   case2Foo1, @function
case2Foo1:
.LFB2:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -20(%rbp)
    movl    -20(%rbp), %eax
    addl    $13, %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE2:
    .size   case2Foo1, .-case2Foo1
    .globl  case2Foo2
    .type   case2Foo2, @function
case2Foo2:
.LFB3:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %eax
    addl    $13, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE3:
    .size   case2Foo2, .-case2Foo2
    .ident  "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
    .section    .note.GNU-stack,"",@progbits

Ther you can see, that the foo2 versions have a few instructions less than the foo1 versions of the functions.你可以看到,foo2 版本比 foo1 版本的函数少了一些指令。

With optimization turned to O3:优化转向O3:
( gcc -S -O3 -o src.S src.c ) ( gcc -S -O3 -o src.S src.c )

    .file   "so_temp.c"
    .text
    .p2align 4,,15
    .globl  case1Foo1
    .type   case1Foo1, @function
case1Foo1:
.LFB0:
    .cfi_startproc
    movl    $18, %eax
    ret
    .cfi_endproc
.LFE0:
    .size   case1Foo1, .-case1Foo1
    .p2align 4,,15
    .globl  case1Foo2
    .type   case1Foo2, @function
case1Foo2:
.LFB5:
    .cfi_startproc
    movl    $18, %eax
    ret
    .cfi_endproc
.LFE5:
    .size   case1Foo2, .-case1Foo2
    .p2align 4,,15
    .globl  case2Foo1
    .type   case2Foo1, @function
case2Foo1:
.LFB2:
    .cfi_startproc
    leal    13(%rdi), %eax
    ret
    .cfi_endproc
.LFE2:
    .size   case2Foo1, .-case2Foo1
    .p2align 4,,15
    .globl  case2Foo2
    .type   case2Foo2, @function
case2Foo2:
.LFB7:
    .cfi_startproc
    leal    13(%rdi), %eax
    ret
    .cfi_endproc
.LFE7:
    .size   case2Foo2, .-case2Foo2
    .ident  "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
    .section    .note.GNU-stack,"",@progbits

both versions are exactly the same.两个版本完全一样。

Still I don't think that this is something you should optimize yourself.我仍然不认为这是你应该优化自己的东西。
In this case readable code should be preferred, especially as code normally isn't compiled with optimizations turned off.在这种情况下,应该首选可读代码,特别是因为代码通常不会在关闭优化的情况下编译。

Case 2 is more efficient, but is often not needed as the compiler is extremely likely to optimize case 1 into case 2.情况 2 更有效,但通常不需要,因为编译器极有可能将情况 1 优化为情况 2。

Go for readability if it doesn't hurt performance (as in this case).如果不影响性能(如本例中),请提高可读性。

Any compiler of at least modest quality will, at even low levels of optimization (such as GCC's -O1 ), compile these to the same code .任何至少具有中等质量的编译器,即使是低级别的优化(例如 GCC 的-O1 ),也会将它们编译为相同的代码 For the most part, any correct optimization you can easily see will be performed by a good compiler.在大多数情况下,您可以轻松看到的任何正确优化都将由良好的编译器执行。

The C standard does not require compilers to mindlessly compile code into instructions that perform the exact steps in the C source code. C 标准不要求编译器无意识地将代码编译为执行 C 源代码中确切步骤的指令。 It only requires compilers to produce code that has the same effects.它只需要编译器生成具有相同效果的代码。 Those effects are defined in terms of observable behavior , which includes the output of the program, interactions with the user, and access to volatile objects (special objects you will learn about later).这些效果是根据可观察行为定义的,包括程序的输出、与用户的交互以及对易失性对象(您将在后面了解的特殊对象)的访问。 Compilers will eliminate things like intermediate variables as long as they can do so without changing the observable behavior.编译器将消除诸如中间变量之类的东西,只要它们可以在不改变可观察行为的情况下这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM