If I'm looping over this many times, would it be faster to use int result = 5 + 10? I often create temporary variables to make my code more readable, for example, if the two variables were obtained from some array using some long expression to calculate the indices. Is this bad performance-wise in C? What about other languages?

Optimizing compiler will change that code to become effectively: int result = 15 ;
– 2501Nov 15 '14 at 19:10

13

Compiler will optimize your code. It's more productive to focus on matters such as (part of) a calculation repeated within a loop that would be better done before the loop begins.
– Weather VaneNov 15 '14 at 19:10

5

I think that he means any temporary variables, i.e.: is using a = b + c; d = a + e; slower than using a = b + c + d + e; it may potentially use more memory if done in ways the compiler can't optimise, but it shouldnt be slower. best focus or work productivity unless it's a commercial and critical performance code.
– com.prehensibleNov 15 '14 at 23:05

@PeteBecker I'm afraid that isn't a productive suggestion. It is quite easy to try something like this and get the wrong impression because you happen to have picked (or failed to pick) a case which is an exception to the general rule. Without a clear understanding of how a compiler works, just testing a few cases should not in any way convince you that it is true for all cases; making such generalisations can be very risky and often leads to error.
– JulesNov 16 '14 at 19:18

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.3Program 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).

I don't think this addresses the question. The example given is simple, but I think the part about “if the two variables were obtained from some array using some long expression to calculate the indices” is more important here, and that can't be optimized away, or can it?
– Arturo Torres SánchezNov 16 '14 at 0:47

1

@ArturoTorresSánchez variables are just a human concept. There are no really variables. What the compiler sees are references to expressions and then the assembly code they are equivalent. When someone asks about variable overhead, really means the memory overhead of the result assembly instructions of that references (such as register/memory read/writes). "Erasing" a variable means if the compiler was smart enough to recognize that there is no reason to reload that "reference" again from memory, since the data is in another reference reachable by it in this context... (1)
– Manu343726Nov 16 '14 at 13:33

1

@ArturoTorresSánchez ... (The array element in this case). And nowadays, compilers are very proficient at global optimizations and expression folding (See the answer bellow about SSA form).
– Manu343726Nov 16 '14 at 13:34

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.

This is the more useful answer. The others went into the constant-folding part of things, rather than the local-copy of a memory location point. Assigning globals and array elements to locals is often helpful when the compiler can't prove that input arrays don't overlap, or that some unknown function being called doesn't can't make changes to the array. This often stops the compiler from reloading the same memory location multiple times.
– Peter CordesAug 5 '15 at 2:08

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).

The point about "as long as the meaning of the program is not changed" is key. There are many cases where two ways of writing a program will have slight semantic differences that might not matter to a programmer, but would require a compiler to generate much less efficient code for one than would be needed for the other.
– supercatNov 15 '14 at 20:42

1

Exactly what supercat said: the compiler can't always prove that two pointers / arrays don't overlap, or that a function call can't change the contents of memory. Thus, it sometimes is forced to generate multiple loads of the same location, but using int a = arr[i] would let the compiler keep the value in a register across function calls and writes through other pointers.
– Peter CordesAug 5 '15 at 2:10

I agree completely with the points made by supercat and Peter Cordes.
– R..Aug 5 '15 at 2:12

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:

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.

The solution is to look at the compiler output for functions that operate on parameters, rather than main() operating on compile-time constants. e.g. here's a simple example of summing a float array, with gcc asm output from godbolt: goo.gl/RxIFEF
– Peter CordesNov 10 '15 at 2:28

I believe that's what I said: "you'd have to look at the assembly output for your particular, non-trivial code". ;)
– ScottNov 10 '15 at 22:08

I was trying to say that you can put pretty trivial code in a function, and see the asm for it. (I think this turned into an argument over the definition of "trivial", which isn't what I intended...). Your example used a function call to generate i and j. My example would be to make i and j function parameters, so they'd be just sitting there in registers at the start of the code for the function.
– Peter CordesNov 10 '15 at 23:03