Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is declaration of variables expensive?

Tags:

c

While coding in C, I came across the below situation.

int function () {   if (!somecondition) return false;    internalStructure  *str1;   internalStructure *str2;   char *dataPointer;   float xyz;    /* do something here with the above local variables */     } 

Considering the if statement in the above code can return from the function, I can declare the variables in two places.

  1. Before the if statement.
  2. After the if statement.

As a programmer, I would think to keep the variable declaration after if Statement.

Does the declaration place cost something? Or is there some other reason to prefer one way over the other?

like image 941
Whoami Avatar asked Jan 01 '15 10:01

Whoami


People also ask

Why variable declaration is important?

1. In programming, a declaration is a statement describing an identifier, such as the name of a variable or a function. Declarations are important because they inform the compiler or interpreter what the identifying word means, and how the identified thing should be used.

What happens when variable declaration?

Variable Declaration in C A variable declaration provides assurance to the compiler that there exists a variable with the given type and name so that the compiler can proceed for further compilation without requiring the complete detail about the variable.

Where is the best place to declare variables?

The recommended practice is to put the declaration as close as possible to the first place where the variable is used. This also minimizes the scope. From Steve McConnell's "Code Complete" book: Ideally, declare and define each variable close to where it's first used.

What is the declaration of a variable?

Declaration of a variable in a computer programming language is a statement used to specify the variable name and its data type. Declaration tells the compiler about the existence of an entity in the program and its location. When you declare a variable, you should also initialize it.


2 Answers

In C99 and later (or with the common conforming extension to C89), you are free to mix statements and declarations.

Just as in earlier versions (only more so as compilers got smarter and more aggressive), the compiler decides how to allocate registers and stack, or do any number of other optimizations conforming to the as-if-rule.
That means performance-wise, there's no expectation of any difference.

Anyway, that was not the reason such was allowed:

It was for restricting scope, and thus reducing the context a human must keep in mind when interpreting and verifying your code.

like image 139
Deduplicator Avatar answered Oct 23 '22 08:10

Deduplicator


Do whatever makes sense, but current coding style recommends putting variable declarations as close to their usage as possible

In reality, variable declarations are free on virtually every compiler after the first one. This is because virtually all processors manage their stack with a stack pointer (and possibly a frame pointer). For example, consider two functions:

int foo() {     int x;     return 5; // aren't we a silly little function now }  int bar() {     int x;     int y;     return 5; // still wasting our time... } 

If I were to compile these on a modern compiler (and tell it not to be smart and optimize out my unused local variables), I'd see this (x64 assembly example.. others are similar):

foo: push ebp mov  ebp, esp sub  esp, 8    ; 1. this is the first line which is different between the two mov  eax, 5    ; this is how we return the value add  esp, 8    ; 2. this is the second line which is different between the two ret  bar: push ebp mov  ebp, esp sub  esp, 16    ; 1. this is the first line which is different between the two mov  eax, 5     ; this is how we return the value add  esp, 16    ; 2. this is the second line which is different between the two ret 

Note: both functions have the same number of opcodes!

This is because virtually all compilers will allocate all of the space they need up front (barring fancy things like alloca which are handled separately). In fact, on x64, it is mandatory that they do so in this efficient manner.

(Edit: As Forss pointed out, the compiler may optimize some of the local variables into registers. More technically, I should be arguing that the first varaible to "spill over" into the stack costs 2 opcodes, and the rest are free)

For the same reasons, compilers will collect all of the local variable declarations, and allocate space for them right up front. C89 requires all declarations to be up-front because it was designed to be a 1 pass compiler. For the C89 compiler to know how much space to allocate, it needed to know all of the variables before emitting the rest of the code. In modern languages, like C99 and C++, compilers are expected to be much smarter than they were back in 1972, so this restriction is relaxed for developer convenience.

Modern coding practices suggest putting the variables close to their usage

This has nothing to do with compilers (which obviously could not care one way or another). It has been found that most human programmers read code better if the variables are put close to where they are used. This is just a style guide, so feel free to disagree with it, but there is a remarkable consensus amongst developers that this is the "right way."

Now for a few corner cases:

  • If you are using C++ with constructors, the compiler will allocate the space up front (since it's faster to do it that way, and doesn't hurt). However, the variable will not be constructed in that space until the correct location in the flow of the code. In some cases, this means putting the variables close to their use can even be faster than putting them up front... flow control might direct us around the variable declaration, in which case the constructor doesn't even need to be called.
  • alloca is handled on a layer above this. For those who are curious, alloca implementations tend to have the effect of moving the stack pointer down some arbitrary amount. Functions using alloca are required to keep track of this space in one way or another, and make sure the stack pointer gets re-adjusted upwards before leaving.
  • There may be a case where you usually need 16-bytes of stack space, but on one condition you need to allocate a local array of 50kB. No matter where you put your variables in the code, virtually all compilers will allocate 50kB+16B of stack space every time the function gets called. This rarely matters, but in obsessively recursive code this could overflow the stack. You either have to move the code working with the 50kB array into its own function, or use alloca.
  • Some platforms (ex: Windows) need a special function call in the prologue if you allocate more than a page worth of stack space. This should not change analysis very much at all (in implementation, it is a very fast leaf function that just pokes 1 word per page).
like image 43
Cort Ammon Avatar answered Oct 23 '22 07:10

Cort Ammon