分配临时变量或计算表达式两次

时间:2016-05-04 18:38:31

标签: c++ c

我正在尝试尽可能高效地编写代码,但我遇到了以下情况:

int foo(int a, int b, int c) 
{
    return (a + b) % c; 
}

一切都好!但是,如果我想检查表达式的结果是否与常量不同,请说myConst。可以说我可以负担一个临时变量。

以下最快的方法是什么方法:

int foo(int a, int b, int c) 
{
    return (((a + b) % c) != myConst) ? (a + b) % c : myException; 
} 

int foo(int a, int b, int c) 
{
    int tmp = (a + b) % c
    return (tmp != myConst) ? tmp : myException; 
}

我无法决定。 '线路在哪里?其中重新计算比分配和解除分配临时变量或反之亦然更为昂贵。

5 个答案:

答案 0 :(得分:14)

不要担心,编写简洁的代码并将微优化保留给编译器。

在您的示例中,两次编写相同的计算很容易出错 - 所以不要这样做。在您的具体示例中,编译器很可能完全避免在堆栈上创建临时值!

您的示例可以(在我的编译器上)生成以下程序集(我已将myConst替换为constexpr 42而myException替换为0):

foo(int, int, int):
        leal    (%rdi,%rsi), %eax       # this adds a and b, puts result to eax
        movl    %edx, %ecx      # loads c
        cltd
        idivl   %ecx  # performs division, puts result into edx
        movl    $0, %eax        #, prepares to return exception value
        cmpl    $42, %edx       #, compares result of division with magic const
        cmovne  %edx, %eax  # overwrites pessimized exception if all is cool
        ret

如你所见,在任何地方都没有临时的信息!

答案 1 :(得分:6)

使用更晚的。

  1. 您没有两次计算相同的值。
  2. 代码更清晰。
  3. 在堆栈上创建局部变量不会花费任何大量时间。

答案 2 :(得分:5)

检查为两个版本生成的汇编程序代码。您很可能希望编译器具有最高的优化设置。

你可能很好地发现编译器本身可以弄清楚中间值是否使用了两次,但只在函数内部,因此可以安全地存储在寄存器中。

答案 3 :(得分:4)

要添加已经发布的内容,调试的简易性至少与代码效率一样重要(如果对代码效率有任何影响,正如其他人发布的那样,不太可能进行优化)。

选择最简单的方法,进行测试和调试。

使用临时变量

如果更多的开发人员使用更简单,非复合的表达式和更多的临时变量,那么帮助就会少得多 - 我无法调试我的代码!'发布到SO。

答案 4 :(得分:0)

硬编码值

以下内容仅适用于硬编码值(即使它们不是constconstexpr

在MSVC 2015的以下示例中,它们已完全优化,仅替换为mov edx, result(在此示例中为= 1):

#include <iostream>
#include <exception>

int myConst{4};
int myException{2};

int foo1(int a,int b,int c)
{
    return (((a + b) % c) != myConst) ? (a + b) % c : myException;
}

int foo2(int a,int b,int c)
{
    int tmp = (a + b) % c;
    return (tmp != myConst) ? tmp : myException;
}

int main()
{
00007FF71F0E1000 48 83 EC 28          sub         rsp,28h  
    auto test1{foo1(5,2,3)};
    auto test2{foo2(5,2,3)};

    std::cout << test1 <<'\n';
00007FF71F0E1004 48 8B 0D 75 20 00 00 mov         rcx,qword ptr [__imp_std::cout (07FF71F0E3080h)]  
00007FF71F0E100B BA 01 00 00 00       mov         edx,1  
00007FF71F0E1010 FF 15 72 20 00 00    call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF71F0E3088h)]  
00007FF71F0E1016 48 8B C8             mov         rcx,rax  
00007FF71F0E1019 E8 B2 00 00 00       call        std::operator<<<std::char_traits<char> > (07FF71F0E10D0h)  
    std::cout << test2 <<'\n';
00007FF71F0E101E 48 8B 0D 5B 20 00 00 mov         rcx,qword ptr [__imp_std::cout (07FF71F0E3080h)]  
00007FF71F0E1025 BA 01 00 00 00       mov         edx,1  
00007FF71F0E102A FF 15 58 20 00 00    call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF71F0E3088h)]  
00007FF71F0E1030 48 8B C8             mov         rcx,rax  
00007FF71F0E1033 E8 98 00 00 00       call        std::operator<<<std::char_traits<char> > (07FF71F0E10D0h)  


    return 0;
00007FF71F0E1038 33 C0                xor         eax,eax  
}
00007FF71F0E103A 48 83 C4 28          add         rsp,28h  
00007FF71F0E103E C3                   ret  

此时其他人已经指出,如果值被传递,或者如果我们有单独的文件,优化将不会发生,但似乎即使代码在单独的编译单元中,优化仍然完成,我们不要&# 39;获得有关这些功能的任何说明:

#include <iostream>
#include <exception>


#include "Header.h"

int main()
{
00007FF667BF1000 48 83 EC 28          sub         rsp,28h  
    int var1{5},var2{2},var3{3};
    auto test1{foo1(var1,var2,var3)};
    auto test2{foo2(var1,var2,var3)};

    std::cout << test1 <<'\n';
00007FF667BF1004 48 8B 0D 75 20 00 00 mov         rcx,qword ptr [__imp_std::cout (07FF667BF3080h)]  
00007FF667BF100B BA 01 00 00 00       mov         edx,1  
00007FF667BF1010 FF 15 72 20 00 00    call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF667BF3088h)]  
00007FF667BF1016 48 8B C8             mov         rcx,rax  
00007FF667BF1019 E8 B2 00 00 00       call        std::operator<<<std::char_traits<char> > (07FF667BF10D0h)  
    std::cout << test2 <<'\n';
00007FF667BF101E 48 8B 0D 5B 20 00 00 mov         rcx,qword ptr [__imp_std::cout (07FF667BF3080h)]  
00007FF667BF1025 BA 01 00 00 00       mov         edx,1  
00007FF667BF102A FF 15 58 20 00 00    call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF667BF3088h)]  
00007FF667BF1030 48 8B C8             mov         rcx,rax  
00007FF667BF1033 E8 98 00 00 00       call        std::operator<<<std::char_traits<char> > (07FF667BF10D0h)  


    return 0;
00007FF667BF1038 33 C0                xor         eax,eax  
}
00007FF667BF103A 48 83 C4 28          add         rsp,28h  
00007FF667BF103E C3                   ret