Initialising Variables

R

Richard Heathfield

santosh said:
Is it also correct to conclude that you have a strong preference for
calloc over malloc?

I can see why you ask, of course. Curiously, however, the answer is "no".
That probably sounds inconsistent. In fact, there are no two ways about it
- it *is* inconsistent!

My "reasoning" (such as it is) is this: either I know exactly how much
memory I need (in which case I allocate exactly that amount and populate it
immediately with good data), or I don't, in which case I allocate more than
I need, populate what I can, and keep track of the first unused slot. This
seems to work for me, and undoubtedly it works for other people here too.
Otherwise, calloc would be much more popular here.

But yes, it's inconsistent. I guess it's a "gut feel" thing - the difference
between int i; and int i = 0; is so small as to be not worth bothering
about, but the difference between int *p = malloc(n * sizeof *p) and int *p
= calloc(n, sizeof *p) clearly depends on n, at least for sufficiently
large n.

So it's a trade-off between debuggability and performance. We all make this
trade-off at some point - we just draw our lines at different places in the
sand, that's all.
 
R

Richard Heathfield

Richard Tobin said:
How do you feel about non-pointer objects that could be used as indices
into an array?

What would you initialise them to? INT_MIN?[/QUOTE]

No, because that wouldn't produce well-defined, guaranteed-reproducible
behaviour. I use 0. Okay, so when that value isn't properly updated with
the eventually-known-correct value I get the wrong answers - but at least I
get the *same* wrong answers on each run, which makes finding the cause
much easier.
 
R

Richard Tobin

Richard Heathfield said:
No, because that wouldn't produce well-defined, guaranteed-reproducible
behaviour. I use 0. Okay, so when that value isn't properly updated with
the eventually-known-correct value I get the wrong answers - but at least I
get the *same* wrong answers on each run, which makes finding the cause
much easier.

Assuming you notice that the answers are wrong.

The idea of INT_MIN of course is to maximise the chance of a fatal error.

-- Richard
 
R

Richard Heathfield

Richard Tobin said:
Assuming you notice that the answers are wrong.

1) Does it compile? Yes? Unit Test: PASSED
2) Does it link? Yes? Integration Test: PASSED
3) Does it crash? No? User Acceptance Test: PASSED
4) Move code into production, take money, run very fast.

Other development models, however, do exist. :)

The idea of INT_MIN of course is to maximise the chance of a fatal error.

It seems to me that what it will actually achieve is a program whose
behaviour is undefined, with one nasty but very possible outcome being a
head-scratching few hours working out why the bug isn't consistently
reproducible.
 
Y

Yevgen Muntyan

Mark said:
Actually, Mr. Tobin and myself consider the opposite approach from yours
to be a reasonable safety precation.

Not in the sense that it makes debugging easier, or that it is
potentially more deterministic at runtime, both of which are highly
debatable and situation-dependent.

Rather, leaving a variable uninitialized (rather than initalize it to a
dummy value) helps both the compiler and the many available static
analysis tools to determine if there is a code path that uses an
unitialized value. The idea is to leverage automated data flow analysis
wherever it is possible.

At the worst, a false positive signifies that the code is too complex,
both for human readers and for compilers / analysis tools. This is
still quite a valuable thing to know.

"Lying to the compiler" is just a synonym for "garbage in, garbage out".
Why prevent the compiler or other analysis tools from helping you by
feeding them garbage?

Because they are too stupid. The code posted by OP can be translated
to this:

#include <stdio.h>

int func (void)
{
return 0;
}

int main (void)
{
int foo;

if (func ())
foo = 8;

printf ("%d\n", foo);
return 0;
}

gcc-4 doesn't warn about this anymore, though gcc-3 did. I am not saying
gcc is the best tool, but it is certainly not one of the worst tools
out there, and it stopped catching such a simple thing.

Doing

int foo = -8;
.....
assert(foo >= 0);

may not necessarily be working, since it may not be executed when you
test the code, but at least you know for sure that it will assert if
it gets to that point.

Maybe you have tools which don't break or something, then you're good.
But then it's certainly not just like "just don't initialize it", it's
rather "leave it unitialized, we run the code through Super Clever
Analyzer which Does Work Right".

Regards,
Yevgen
 
M

Mark F. Haigh

Richard said:
Richard Tobin said:




1) Does it compile? Yes? Unit Test: PASSED
2) Does it link? Yes? Integration Test: PASSED
3) Does it crash? No? User Acceptance Test: PASSED
4) Move code into production, take money, run very fast.

Other development models, however, do exist. :)

Noted.

However, consider the case where the business acceptability critera can
be simply stated as: "is the code as flawless as humanly possible?".

With so much multimedia (video, audio, 3d acceleration, physics
libraries), networking (gigabit switch fabrics, 10Gb ethernet, crypto
coprocessors), and computer architecture (multi-cored CPUs, advent of
cheap >= 8x SMP systems, NUMA architectures) advances, there's a whole
lot of C code that must run as reliably as humanly possible. Much of it
has needed updating in recent years due to advances in various technologies.

When the code in question is figuring out how to arrange disk blocks,
doing network security filtering, or simply mapping a physical page to a
virtual page, it had better be correct.

All I'm trying to say is that 90% of the time, any way you can put
yourself into a situation where a tool or automated process can help you
is a good thing. There are exceptions, but in general, the more the better.

What you are describing mirrors the tradeoffs your clients are willing
to make, and that's fine. But different clients want different things.
It seems to me that what it will actually achieve is a program whose
behaviour is undefined, with one nasty but very possible outcome being a
head-scratching few hours working out why the bug isn't consistently
reproducible.

If you'd stop writing those bugs, we wouldn't have to have this
conversation, now would we?


Mark F. Haigh
(e-mail address removed)
 
G

Guest

Richard said:
Harald van D?k said:


It becomes a disadvantage when *other people* use it, even though I don't
like it, if I have to read their stuff later on.

That can't be what CBFalconer meant, since that makes it impossible to
ignore the feature.
 
R

Richard Heathfield

Mark F. Haigh said:

What you are describing mirrors the tradeoffs your clients are willing
to make, and that's fine. But different clients want different things.

Absolutely, and in any case different programmers work in different ways,
and different strategies work for different people. There is no One Right
Way to program (although of course there are plenty of wrong ways).
If you'd stop writing those bugs, we wouldn't have to have this
conversation, now would we?

Noted. I'll start writing perfect code right away. (Sheesh. I wish you'd
suggested this earlier.)
 
R

Richard Heathfield

Harald van D?k said:
That can't be what CBFalconer meant, since that makes it impossible to
ignore the feature.

Which leaves open the question of what he /did/ mean, I guess.
 
C

CBFalconer

Richard said:
Harald van D?k said:
.... snip ...

Which leaves open the question of what he /did/ mean, I guess.

Partly I was being humourous, by simply adding 'dis'. In addition,
I prefer to have all the variables laid out in one place, possibly
with comments describing their reasons for existing, etc. Instead
I see 268 lines (not including this) of needless responses, which
was not my intent :)

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
 
K

Keith Thompson

santosh said:
It _might_ be useful. As I said, in my experience so far, the choice of
whether to initialise or not really depends on a case by case basis.

As other posters have noted, using a default value, will likely produce
a reproducable bug, if the concerned object is not reinitialised
properly, instead of leading to varying behaviour. The value will also
be easier to spot in a debugging session.

Yes, but a default value (unless you can choose one that's guaranteed
to be invalid) can also mask a bug.

Suppose you initialize a variable with some default value, you intend
to compute a new value for it, but you fail to do so (that's the bug.
If the default value allows the code to execute but produce quietly
incorrect results, it's going to be difficult to track down the
problem. If you had left off the initialization, your compiler
*might* have been able to warn you that you're using a possibly
uninitialized variable, or the random garbage in the variable *might*
have caused a more drastic failure during testing (as opposed to a
subtle failure that's still there in the shipped product).
Interesting points on both sides.

Yes.
 
K

Keith Thompson

Ian Collins said:
Richard Heathfield wrote: [...]
I don't agree that the language feature (defining objects at
arbitrary[1] points) eliminates the problem, though. The simplest
example I can think of is when the appropriate value for an object
depends on conditions which cannot be (or at least have not been
and are unlikely to be) reduced to a single expression.
Maybe not all of them, but probably the majority. There will always be
the exceptions that prove the rule.
[...]

Exceptions don't prove rules. See, for example,
<http://www.worldwidewords.org/qa/qa-exc1.htm>.
 
K

Keith Thompson

Yevgen Muntyan said:
Because they are too stupid. The code posted by OP can be translated
to this:

#include <stdio.h>

int func (void)
{
return 0;
}

int main (void)
{
int foo;

if (func ())
foo = 8;

printf ("%d\n", foo);
return 0;
}

gcc-4 doesn't warn about this anymore, though gcc-3 did. I am not saying
gcc is the best tool, but it is certainly not one of the worst tools
out there, and it stopped catching such a simple thing.

gcc 3.4.4 produces a warning with "-O1" or higher. gcc 4.1.1 produces
a warning with "-O3" or higher.

Apparently something was changed in the optimization code, so that you
need a higher optimization level to cause gcc to do the dataflow
analysis necessary to catch the bug.

In general, you should probably compile with the highest possible
optimization level to catch as many errors as you can. (If you don't
trust the higher optimization levels to give you correct code, you can
always recompile at a lower level.)
 
I

Ian Collins

Yevgen said:
Because they are too stupid. The code posted by OP can be translated
to this:

#include <stdio.h>

int func (void)
{
return 0;
}

int main (void)
{
int foo;

if (func ())
foo = 8;

printf ("%d\n", foo);
return 0;
}

gcc-4 doesn't warn about this anymore, though gcc-3 did. I am not saying
gcc is the best tool, but it is certainly not one of the worst tools
out there, and it stopped catching such a simple thing.
Invest in a decent lint if your tools don't include one. Splitting the
burden between two tools is a good idea.
 
I

Ian Collins

Keith said:
Ian Collins said:
Richard Heathfield wrote:
[...]
I don't agree that the language feature (defining objects at
arbitrary[1] points) eliminates the problem, though. The simplest
example I can think of is when the appropriate value for an object
depends on conditions which cannot be (or at least have not been
and are unlikely to be) reduced to a single expression.

Maybe not all of them, but probably the majority. There will always be
the exceptions that prove the rule.

[...]

Exceptions don't prove rules. See, for example,
<http://www.worldwidewords.org/qa/qa-exc1.htm>.
Now that's just being overly pedantic. While not being mathematically
correct, the expression is in widespread use.
 
K

Keith Thompson

Ian Collins said:
Keith said:
Ian Collins said:
Richard Heathfield wrote:
[...]

I don't agree that the language feature (defining objects at
arbitrary[1] points) eliminates the problem, though. The simplest
example I can think of is when the appropriate value for an object
depends on conditions which cannot be (or at least have not been
and are unlikely to be) reduced to a single expression.


Maybe not all of them, but probably the majority. There will always be
the exceptions that prove the rule.

[...]

Exceptions don't prove rules. See, for example,
<http://www.worldwidewords.org/qa/qa-exc1.htm>.
Now that's just being overly pedantic. While not being mathematically
correct, the expression is in widespread use.

<OT>
The expression may be in widespread use, but the way it's commonly
used is simply wrong. This is not pedantry; it just doesn't make any
sense at all. It's exactly the opposite of the truth.
</OT>
 
R

Richard Heathfield

Keith Thompson said:

Yes, but a default value (unless you can choose one that's guaranteed
to be invalid) can also mask a bug.

How so? Surely it will lead to incorrect results?
Suppose you initialize a variable with some default value, you intend
to compute a new value for it, but you fail to do so (that's the bug.
If the default value allows the code to execute but produce quietly
incorrect results, it's going to be difficult to track down the
problem.

I disagree. Your clue is that the results are incorrect. From there, it's
just a matter of finding out why. In my experience, this is a lot easier
when the results are reproducible.
If you had left off the initialization, your compiler
*might* have been able to warn you that you're using a possibly
uninitialized variable, or the random garbage in the variable *might*
have caused a more drastic failure during testing

Yes, but I see a lot of "might"s in there. If you could guarantee this
behaviour, I'd be a lot happier.
(as opposed to a
subtle failure that's still there in the shipped product).

If so, then that's a failure of one's testing process, since one's testers
clearly assume that any run not resulting in a crash is a successful run.
Well, testers, here's your final production code:

int main(void) { return 0; }

It doesn't crash. Hey, it must be right!
 
K

Keith Thompson

Richard Heathfield said:
Keith Thompson said:



How so? Surely it will lead to incorrect results?

Incorrect results can be arbitrarily subtle and difficult to detect,
especially if it's not obvious before you run the program what the
results *should* be.

[...]
Yes, but I see a lot of "might"s in there. If you could guarantee this
behaviour, I'd be a lot happier.

Agreed.
 
R

Richard Heathfield

Keith Thompson said:
Incorrect results can be arbitrarily subtle and difficult to detect,
especially if it's not obvious before you run the program what the
results *should* be.

I understand what you're saying, but I'm struggling to understand why you're
saying it. Yes, incorrect results can be arbitrarily subtle and difficult
to detect. Does that mean we're allowed to produce incorrect results, or
not? If we're /not/ allowed to produce incorrect results, then our testing
had better be able to spot arbitrarily subtle output errors. And if we
/are/ allowed to produce incorrect results, then you won't be disappointed
with the performance of int main(void) { return 0; }
 

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
473,774
Messages
2,569,600
Members
45,180
Latest member
CryptoTax Software
Top