我正在尝试尽可能高效地编写代码,但我遇到了以下情况:
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;
}
我无法决定。 '线路在哪里?其中重新计算比分配和解除分配临时变量或反之亦然更为昂贵。
答案 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)
使用更晚的。
答案 2 :(得分:5)
检查为两个版本生成的汇编程序代码。您很可能希望编译器具有最高的优化设置。
你可能很好地发现编译器本身可以弄清楚中间值是否使用了两次,但只在函数内部,因此可以安全地存储在寄存器中。
答案 3 :(得分:4)
要添加已经发布的内容,调试的简易性至少与代码效率一样重要(如果对代码效率有任何影响,正如其他人发布的那样,不太可能进行优化)。
选择最简单的方法,进行测试和调试。
使用临时变量
如果更多的开发人员使用更简单,非复合的表达式和更多的临时变量,那么帮助就会少得多 - 我无法调试我的代码!'发布到SO。
答案 4 :(得分:0)
以下内容仅适用于硬编码值(即使它们不是const
或constexpr
)
在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