When to initialize the local variables?

S

Sriram Rajagopalan

Hi,

Which of these two would be a better way of initializing the local
variables? and why?

1) At the time of their declaration.

Eg:

void func()
{
int i =0;

/* Some code follows */
i = <actual_value_of_i>;
}


2) Just before their use.

Eg:

void func()
{
int i;

/* Some code follows */
i = <actual_value_of_i>; /* "i " is initialized now */
}

Please advice.

Thanks,
Sriram.
 
M

MQ

Sriram said:
Hi,

Which of these two would be a better way of initializing the local
variables? and why?

1) At the time of their declaration.

Eg:

void func()
{
int i =0;

/* Some code follows */
i = <actual_value_of_i>;
}


2) Just before their use.

Eg:

void func()
{
int i;

/* Some code follows */
i = <actual_value_of_i>; /* "i " is initialized now */
}

Please advice.

Thanks,
Sriram.

It doesn't matter when you initialize a variable, as long as you do NOT
read the variable and use it's value before it is initialized. The
second case is probably the best, since in the first case you are
initializing i twice, which is redundant. Not that this really matters
anyway, since the compiler would optimize such redundancy out most
likely. However, if you know the value of i at the point of
declaration, why not do it at that point? It really is a matter of
taste and also depends on the situation.

MQ
 
S

santosh

Sriram said:
Hi,

Which of these two would be a better way of initializing the local
variables? and why?

1) At the time of their declaration.

Eg:
void func()
{
int i =0;
/* Some code follows */
i = <actual_value_of_i>;
}

2) Just before their use.

Eg:
void func()
{
int i;
/* Some code follows */
i = <actual_value_of_i>; /* "i " is initialized now */
}

Please advice.

Method 1. leads to safer code, method 2. leads to negligibly faster
code. Method 2. might lead to negligibly more readable code, or might
not, depending on the programmer's tastes.
 
C

Chris Dollin

Sriram said:
Hi,

Which of these two would be a better way of initializing the local
variables? and why?

1) At the time of their declaration.

Eg:

void func()
{
int i =0;

/* Some code follows */
i = <actual_value_of_i>;
}


2) Just before their use.

Eg:

void func()
{
int i;

/* Some code follows */
i = <actual_value_of_i>; /* "i " is initialized now */
}

Please advice.

("Advi/s/e". Advice is what gets given; advise is what gets done.)

Neither of the above examples.

(3) When they are declared, in their declaration, to their actual value.

void func()
{
int i = <actual value of i>;
}

This is easiest in C99, which had a sudden attack of sanity and allowed
declarations after statements, but even in C90 you can get pretty close
to this without uglifying your code [1]. Then it's only the exceptional
cases that need thinking at read-time.

[1] Too much.
 
T

Tom St Denis

santosh said:
Method 1. leads to safer code, method 2. leads to negligibly faster
code. Method 2. might lead to negligibly more readable code, or might
not, depending on the programmer's tastes.

Method 1 == stupid if your function has [say] 15 auto variables.

I give you for instance

int ccm_memory(int cipher,
const unsigned char *key, unsigned long keylen,
symmetric_key *uskey,
const unsigned char *nonce, unsigned long noncelen,
const unsigned char *header, unsigned long headerlen,
unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
unsigned char *tag, unsigned long *taglen,
int direction)
{
unsigned char PAD[16], ctr[16], CTRPAD[16], b;
symmetric_key *skey;
int err;
unsigned long len, L, x, y, z, CTRlen;
....

There are 12 autos (most of which are re-used throughout the protocol,
hence the really specific names like "x" and "y"). Adding a default
initializer to all of them is a pain in the arse and would end up with
code like

unsigned char PAD[16] = {0}, ctr[16] = {0}, CTRPAD[16] = {0}, b =
0;
symmetric_key *skey = NULL;
int err = CRYPT_OK;
unsigned long len = 0, L = 0, x = 0, y = 0, z = 0, CTRlen = 0;

Which isn't exactly easier to read, nor really safer.

If you want to avoid uninitialized reads, use a tool like valgrind.

Tom
 
R

Richard Bos

Neither of the above examples.

(3) When they are declared, in their declaration, to their actual value.

void func()
{
int i = <actual value of i>;
}

Which is rarely actually possible, since most often the value of one
initialiser depends on a computation involving another, or even on user
input.
This is easiest in C99, which had a sudden attack of sanity and allowed
declarations after statements,

Leading to maintenance programmers having to grope through your code to
find out where you hid the declarations this time. No, thanks.

Richard
 
C

Chris Dollin

Richard said:
Which is rarely actually possible, since most often the value of one
initialiser depends on a computation involving another, or even on user
input.

I can't speak for your code, of course, but in what C code I write,
it's /usually/ possible, as in, most of my (auto) declarations have the
variables given their proper initial working values.

It doesn't matter if an initialiser depends on the value of another
variable: that just means the declarations have to be in the
right order. (The corresponding statements in the declare-then-assign
idiom have to be in the right order, so this isn't an onerous requirement.)
It doesn't even matter if they depend on user input (since that gets
abstracted out into functions).
Leading to maintenance programmers having to grope through your code to
find out where you hid the declarations this time. No, thanks.

If the functions are big enough to need groping, the maintenance
programmer already has problems. A forest of uninitialised
declarations at the top of functions (or blocks) is equally opaque.
IMAO.

I wonder what the differences are in coding approach that lead to
these differing attitudes?
 
C

Clever Monkey

Sriram said:
Hi,

Which of these two would be a better way of initializing the local
variables? and why?

1) At the time of their declaration.
[...]

2) Just before their use.
It depends. This is mostly syntactic sugar, but it can (IMHO) make code
more readable and understandable. For example, if I have a typical "one
entry, one exit" function, I often set the variable the holds the exit
value right up front with some sensible default. This tells the reader
that if the function "falls through" it will be set to some default.

Conversely, when I'm using a variable used as a temporary or iterator
which must be reset to some value, I usually set/reset it just before use.

If a variable is just going to be clobbered by some function return, I
never initialize it. [An aside for the gurus: can the compiler optimize
away a spurious initializations? I'm thinking of a case where an
initializer once made sense, but then the next use of the variable is a
holder for a function return. Will some compilers know to optimize the
initialization?]
 
R

Richard Heathfield

Sriram Rajagopalan said:
Hi,

Which of these two would be a better way of initializing the local
variables? and why?

1) At the time of their declaration.
2) Just before their use.

Well, you now know from reading the other responses that 1) is stupid and 2)
is stupid. You've been shown a 3) which is, naturally, stupid. And yet it's
hard to imagine a 4), isn't it?

So you have to make a judgement call.

Let's wrap up (3) into (1), since they are basically the same - i.e. "give
it the best you've got, at definition time". So:

Method 1 - initialise all auto objects to some default value unless their
proper starting value is actually known at definition time. This has the
advantage that, in the event of your (incorrectly) using a value before its
proper starting value has been calculated, the behaviour of the program is
deterministic and therefore easier to debug.

Method 2 - leave auto objects in an indeterminate state until their proper
starting value is known. This has the advantage, on some implementations,
that incorrectly using an indeterminate value may, if you are fortunate,
lead to the program "crashing", "segfaulting", "coredumping",
"access-violating", or call it what you will, leading to early detection -
but this is far from guaranteed. It has the further potential advantage of
being microscopically faster. Furthermore, *some* (but not all) compilers
can detect *some* (but not all) usages of indeterminate values, giving a
touch of reassurance which may or may not comfort you.

Which you choose is up to you. Personally, I favour Method 1, but I
recognise that there are some genuinely expert programmers in this
newsgroup who prefer Method 2. I respect their choice, and they respect
mine. Both approaches are valid, and to some extent your choice will depend
on other aspects of your programming style (for example, whether your
functions are typically short or long!).

Like I said, it's a judgement call. It is not as clear-cut as some of the
other responses have suggested.
 
P

pete

Sriram said:
Hi,

Which of these two would be a better way of initializing the local
variables? and why?

1) At the time of their declaration.
2) Just before their use.

I prefer to initialize just before use.

I'm accustomed to compilers that warn of unused variables.
My preference is to not have unused variables remaining in the code.

"1) At the time of their declaration" silences the warning,
so I prefer to initialize just before use.
 
S

santosh

pete said:
I prefer to initialize just before use.

I'm accustomed to compilers that warn of unused variables.
My preference is to not have unused variables remaining in the code.

"1) At the time of their declaration" silences the warning,
so I prefer to initialize just before use.

/* t2.c */
#include <stdio.h>

int main(void) {
int a = 5, b, c = 10;

while(c < 20)
printf("%d\n", c);

return 0;
}
/* end */

$ gcc -Wall -Wextra -ansi -pedantic -o t2 t2.c
t2.c : In function: 'main'
t2.c:4: warning: unused variable 'b'
t2.c:4: warning: unused variable 'a'
$
 
C

CBFalconer

Richard said:
.... snip ...

Method 1 - initialise all auto objects to some default value unless
their proper starting value is actually known at definition time.
This has the advantage that, in the event of your (incorrectly)
using a value before its proper starting value has been calculated,
the behaviour of the program is deterministic and therefore easier
to debug.

Alternatively, it postpones the eventual blow-up to a remote
statement, and thus conceals the cause of the bug. Alternative
two, the faulty initialization never causes a blow-up, but simply
creates bad output. This is not detected for three years, after
having caused twenty-eight unnecessary deaths. Alternative three,
the extra initialization defeats the systems default trap value
initialization, preventing early detection and correction.
From which you may gather that I am not a fan of shotgun
initialization.
 
R

Richard Tobin

Which of these two would be a better way of initializing the local
variables? and why?

I wouldn't give a hard-and-fast rule, but here are some considerations
I haven't seen mentioned elsewhere in the thread:

(1) don't initialise variables if the value is never used. For example,
don't do this:

int val = 0;
... lots of code not using val ...
val = f(...);

The initialisation will just confuse a reader who wonders what it's
used for.

(2) if you have to violate (1) explain why. For example, if you want
to avoid a compiler warning when the compiler suspects,
incorrectly, that a variable is used uninitialised, put a comment
by the initialisation:

void *p = 0; /* because gcc thinks it's used uninitialised */

(3) if you can't initialise one of a group of related variables, don't
initialise any. For example, don't do this:

int start=1, step, end;
...
step = f(...);
end = g(...);
for(i=start; i<end; i+=step)
...;

Instead assign to start before the loop. It's annoying to have to
look at two places to find information that belongs together.

(4) don't initialise a variable that you re-use, and have to
"reinitialise". For example, don't do this:

Link *p = head;
...
while(*p)
...;
p = head;
while(*p)
...;

It creates a spurious non-symmetry between the two uses, obscuring their
similarity.

-- Richard
 
K

kyle york

Greetings,

Sriram said:
Hi,

Which of these two would be a better way of initializing the local
variables? and why?

1) At the time of their declaration.

Eg:

void func()
{
int i =0;

/* Some code follows */
i = <actual_value_of_i>;
}


2) Just before their use.

Eg:

void func()
{
int i;

/* Some code follows */
i = <actual_value_of_i>; /* "i " is initialized now */
}

If you happen to be fortunate enough to use an implementation that will
flag `used before assigned' the second is better since the compiler will
let you know if you've made a logic error.

If not, the first is safer.
 
R

Richard Heathfield

CBFalconer said:
Alternatively, it postpones the eventual blow-up to a remote
statement, and thus conceals the cause of the bug.

Not so. We are all accustomed to back-tracking from a symptom to a cause,
are we not?
Alternative
two, the faulty initialization never causes a blow-up, but simply
creates bad output. This is not detected for three years, after
having caused twenty-eight unnecessary deaths.

Don't you ever test your programs?
Alternative three,
the extra initialization defeats the systems default trap value
initialization, preventing early detection and correction.

From which you may gather that I am not a fan of shotgun
initialization.

Hence your choice of terminology - "shotgun" indeed! :)

Personally, I'm not a fan of undefined behaviour. Give me a *reproducible*
bug every time.
 
H

Hallvard B Furuseth

kyle said:
If you happen to be fortunate enough to use an implementation that
will flag `used before assigned' the second is better since the
compiler will let you know if you've made a logic error.

If not, the first is safer.

Yes. Sometimes the compiler can't figure it out for sure though. In
case of gcc -Wall, it then warns that a variable _may_ be used
uninitialized.

I usually see if I can reorganize such code so gcc can tell that the
variable is initialized before use. E.g. for() -> do..while(), or pick
one possible value as the default, or default:assert(0); in a switch().
Otherwise I may add a useless initialization just to silence the warning
- with a comment that it _is_ just supposed to to silence the warning.
 
H

Hallvard B Furuseth

I forgot one detail: The point isn't to initialize just before use if
you go that path, but to set the value around the place in the function
where it locically seems to belong. If there is such a place.
 
C

Chris Torek

If a variable is just going to be clobbered by some function return, I
never initialize it. [An aside for the gurus: can the compiler optimize
away a spurious initializations? I'm thinking of a case where an
initializer once made sense, but then the next use of the variable is a
holder for a function return. Will some compilers know to optimize the
initialization?]

Given code like:

T var = initial;
... code that does not use var ...
var = result;

standard dataflow optimization techniques (there are several) will
all get rid of the redundant assignment. The initialization will
not disappear if you do something like this instead, though:

T var = initial;
... code that, while it does not use var, does use &var ...
var = result;

In this case, the use of "&var" can defeat attempts to follow the
points at which var is used and/or set. (If the address-of operator
can be removed by other optimizations, the dataflow techniques can
once again recover the points at which the variable is first used
and first defined, and remove the "= initial" part if it is in fact
redundant.)

Since C's arrays are generally turned into pointers internally,
most cases of:

T arr[N] = { initial };
... code that does not use arr for any i ...
arr = result; /* for some valid i */

are not optimized away except by particularly smart compilers.
 
M

MQ

Chris said:
(3) When they are declared, in their declaration, to their actual value.

Surely this is not always possible, say, when the variable is
initialised by a call to a function. Think scanf()...
 
M

MQ

Chris said:
(3) When they are declared, in their declaration, to their actual value.

Surely this is not always possible, say, when the variable is
initialised by a call to a function. Think scanf()...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,262
Messages
2,571,043
Members
48,769
Latest member
Clifft

Latest Threads

Top