临时变量会降低程序的速度吗?

假设我有以下 C 代码:

int i = 5;
int j = 10;
int result = i + j;

如果我循环这么多次,使用 int result = 5 + 10会不会更快?我经常创建临时变量来使我的代码更具可读性,例如,如果这两个变量是从某个数组中使用某个长表达式来计算索引的话。这在 C 语言中是不是很糟糕?其他语言呢?

7824 次浏览

A modern optimizing compiler should optimize those variables away, for example if we use the following example in godbolt with gcc using the -std=c99 -O3 flags (see it live):

#include <stdio.h>


void func()
{
int i = 5;
int j = 10;
int result = i + j;


printf( "%d\n", result ) ;
}

it will result in the following assembly:

movl    $15, %esi

for the calculation of i + j, this is form of constant propagation.

Note, I added the printf so that we have a side effect, otherwise func would have been optimized away to:

func:
rep ret

These optimizations are allowed under the as-if rule, which only requires the compiler to emulate the observable behavior of a program. This is covered in the draft C99 standard section 5.1.2.3 Program execution which says:

In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).

Also see: Optimizing C++ Code : Constant-Folding

While all sorts of trivial differences to the code can perturb the compiler's behavior in ways that mildly improve or worsen performance, in principle it it should not make any performance difference whether you use temp variables like this as long as the meaning of the program is not changed. A good compiler should generate the same, or comparable, code either way, unless you're intentionally building with optimization off in order to get machine code that's as close as possible to the source (e.g. for debugging purposes).

This is an easy task to optimize for an optimizing compiler. It will delete all variables and replace result with 15.

Constant folding in SSA form is pretty much the most basic optimization there is.

The example you gave is easy for a compiler to optimize. Using local variables to cache values pulled out of global structures and arrays can actually speed up execution of your code. If for instance you are fetching something from a complex structure inside a for loop where the compiler can't optimize and you know the value isn't changing, the local variables can save quite a bit of time.

You can use GCC (other compilers too) to generate the intermediate assembly code and see what the compiler is actually doing.

There is discussion of how to turn on the assembly listings here:Using GCC to produce readable assembly?

It can be instructive to examine the generated code and see what a compiler is actually doing.

You're suffering the same problem I do when I'm trying to learn what a compiler does--you make a trivial program to demonstrate the problem, and examine the assembly output of the compiler, only to realize that the compiler has optimized everything you tried to get it to do away. You may find even a rather complex operation in main() reduced to essentially:

push "%i"
push 42
call printf
ret

Your original question is not "what happens with int i = 5; int j = 10...?" but "do temporary variables generally incur a run-time penalty?"

The answer is probably not. But you'd have to look at the assembly output for your particular, non-trivial code. If your CPU has a lot of registers, like an ARM, then i and j are very likely to be in registers, just the same as if those registers were storing the return value of a function directly. For example:

int i = func1();
int j = func2();
int result = i + j;

is almost certainly to be exactly the same machine code as:

int result = func1() + func2();

I suggest you use temporary variables if they make the code easier to understand and maintain, and if you're really trying to tighten a loop, you'll be looking into the assembly output anyway to figure out how to finesse as much performance out as possible. But don't sacrifice readability and maintainability for a few nanoseconds, if that's not necessary.