What a stupid gcc!

N

Noob

BartC said:
But what happens when the code defines a variable two pages into a function,
but you happen to be reading some code using that same variable four pages
into the function! Where do you go to find the definition? At the start of a
function is usually a good place! You don't always know that a variable is
only used once.

Functions should NEVER be 5 pages long.
And with blocks having their own scope (?) the same name can be used more
than once with different definitions; even more confusing.

Wow, I have a solution for that one! Don't reuse variable names
within a function.

And let me blow your mind, within an inner block, you can "shadow"
definitions from outer blocks (declare a new variable with the same
name). And that's bad practice too.

These are QoP (Quality of Programmer) issues.

If one is actively trying to write obfuscated code, nothing
can be done to educate them, except for the clue bat.

cf. also http://www.ioccc.org/
 
J

Jorgen Grahn

But what happens when the code defines a variable two pages into a function,
but you happen to be reading some code using that same variable four pages
into the function!

Then it's refactoring time. But IME the usual case is that a few
variables need function scope and the rest need only a quite narrow
scope down inside some loop or if ... else.

I'm not a fan of huge functions (who is?) but with proper variable
scope (and the things that follow: being able to apply 'const' and
initialize them at the declaration) you can make them much more
pleasant to work with. Breaking down the huge function into smaller
ones is a much bigger effort/risk, especially when maintaining old
code.

/Jorgen

PS. I also agree with what some other posters wrote.
 
J

Jorgen Grahn

It may be a sign of my age and when I learned C, but I really like
defining all my variables, and then using them.

Might be a generation thing ... I learned C around 1992. But I've also
used C++ heavily in recent years; I guess that's where I learned not
to introduce variables until I need them.
If defining a variable
at the start of a block other than the start of the function (and not as
the iterator of a for loop) makes sense, it's a really good clue my
function is too long.

If my variables are first used two pages down, the function is almost
certainly too long. If "two pages down" is even a relevant phrase, my
function is almost certainly too long.

Yes, of course. But if you're working in teams, it's not always your
fault the function looks like this, and "right now" may not be the
right time to break it down.

/Jorgen
 
B

BartC

James Kuyper said:
Backwards from the point of use, until I find a definition. It's the
only safe direction to look, and I'll get to the definition a lot
quicker that way if it's closer to the point of use.

That means looking at every line of code before that point, for a variable
name that be similar to many others. Declarations at the start of a function
are easier for low-tech editors (even with one that can't switch quickly
between two locations, probably you can run two instances of it).
I find it quite easy to determine that; usually during design,
definitely by the time I've finished coding. The future reader doesn't
need to know this in order to perform his search, just search backwards
from the point of use.

Look at this example from the middle of a function (from Python sources):

mz = z->ob_type->tp_as_number;

Applying a local declaration, and let's say you're lucky and this the first
use of mz you see, it might look like:

PyNumberMethods mz = z->ob_type->tp_as_number;

That's great; we know what mz is. Except that's not the full picture. The mz
variable is actually declared like this at the top of the function:

PyNumberMethods *mv, *mw, *mz;

Now we know there are three related variables, and there aren't any called
mx or my. Which can give an extra dimension to our knowledge (there are
parameters v, w, z, and mv, mw, and mz presumably correspond to these). It
also tells us that mx and my are available for other purposes.

With a smart IDE, and careful perusal, you would become aware of all this
anyway. But burying the details about local variables in a dozen assorted
places just obfuscates things and life a bit more difficult.

I was going to say that making in-place declarations makes things easier to
write, harder to read, but then imagine having to clutter your code with
three lots 'PyNumberMethods' instead of one!
 
J

James Kuyper

As others have pointed out, this indicates that your function is
probably too long to be well-understood.
That means looking at every line of code before that point,

I suppose so, but it's the backward-search feature of my text editor
that does the looking, it's not at all tedious for me.
... for a variable
name that be similar to many others.

Similarity doesn't matter to the backwards-search feature. Just cut and
paste the variable name into the search pattern, and you'll guarantee
it's the one you're looking for. If you can't find it, there's been a
misspelling. Choose the "whole words only" option (if available in your
editor), and you won't have to worry about false positives from other
identifiers whose names contain that variable's name.
... Declarations at the start of a function
are easier for low-tech editors (even with one that can't switch quickly
between two locations, probably you can run two instances of it).

My favorite editor (vi) is fairly low tech, and available just about
everywhere I need it; you may be less lucky. I don't think anyone should
settle for using a editor on a modern (in this case, modern means post
1980's) system that's not capable of backwards search.

Note: I would not recommend vi for new users; the learning curve is
quite steep, GUI editors are much easier to use, particularly if built
into an IDE. However, I've already learned it, and once you've learned
them, the power of vi's commands can be quite addictive. I've never seen
a GUI editor (other than gvim, which doesn't really count) where I could
do all (or even most) of the things I can do with vi commands.
Look at this example from the middle of a function (from Python sources):

mz = z->ob_type->tp_as_number;

Applying a local declaration, and let's say you're lucky and this the first
use of mz you see, it might look like:

PyNumberMethods mz = z->ob_type->tp_as_number;

That's great; we know what mz is. Except that's not the full picture. The mz
variable is actually declared like this at the top of the function:

PyNumberMethods *mv, *mw, *mz;

Now we know there are three related variables, and there aren't any called
mx or my. Which can give an extra dimension to our knowledge (there are
parameters v, w, z, and mv, mw, and mz presumably correspond to these). It
also tells us that mx and my are available for other purposes.

With a smart IDE, and careful perusal, you would become aware of all this
anyway. But burying the details about local variables in a dozen assorted
places just obfuscates things and life a bit more difficult.

My experience is the opposite. Putting declarations closer to the point
of use highlights them, it doesn't bury them in a huge pile of other
variables. Knowing that a given variable will be used only in one
particular inner scope makes it easier to understand it's meaning, not
harder.

Of course, the best way to document the meaning of a variable is with a
comment on the line where it's declared, or if there's not enough room
for that, on the previous or following line (it doesn't matter which,
but it does matter that the choice of 'previous' or 'following' be
consistent throughout a given body of code).
I was going to say that making in-place declarations makes things easier to
write, harder to read, but then imagine having to clutter your code with
three lots 'PyNumberMethods' instead of one!

I often will do that even if they were all declared at the top of the
same block; only if they were all closely related variables of the same
type with short names would I merge their declarations like that. And if
those conditions are met, I'd carefully consider whether they should be
elements of a single array, rather than separate variables.

Using multiple declarations also often allows enough room for a short
descriptive comment on the declaration line.
 
G

gwowen

I've never seen a GUI editor (other than gvim, which doesn't really count)
where I could do all (or even most) of the things I can do with vi commands.

*cough*

M-x all-hail-emacs
 
R

Rich Webb

My favorite editor (vi) is fairly low tech, and available just about
everywhere I need it; you may be less lucky. I don't think anyone should
settle for using a editor on a modern (in this case, modern means post
1980's) system that's not capable of backwards search.

Note: I would not recommend vi for new users; the learning curve is
quite steep, GUI editors are much easier to use, particularly if built
into an IDE. However, I've already learned it, and once you've learned
them, the power of vi's commands can be quite addictive. I've never seen
a GUI editor (other than gvim, which doesn't really count) where I could
do all (or even most) of the things I can do with vi commands.

As a long-time vi user (from 'way back in the dark ages) and current
gvim-er, I agree of course. However, Notepad++ (aka npp) is FOSS and
also worth having around. It's pretty decent, as editors go. The visual
diff is quite handy. Windows only, though. http://notepad-plus-plus.org/

And, oh yeah, it will do a backwards search... ;-)
 
J

James Kuyper

*cough*

M-x all-hail-emacs

You're right, of course, emacs is a GUI with powerful commands, and I
forgot about it.
I once spent an entire year using it as my main editor, partly because
it was one of the few available on the platform I was using at the time,
and vi wasn't, but also to give myself a decent chance to get used to
it. I never did. I no longer remember the details, but I remember having
a great deal of trouble remembering the syntax for the emacs equivalent
of vi's global search-and-replace:

g/pattern/s/original/replacement/g

Whatever the actual syntax was, I found it counterintuitive (not that
I'd claim that the vi syntax is obvious - but I'm used to vi). What was
worse is that I remember having even more trouble locating help
explaining that syntax, and that's a problem with help system, not with
my memory.
 
I

ImpalerCore

As a long-time vi user (from 'way back in the dark ages) and current
gvim-er, I agree of course. However, Notepad++ (aka npp) is FOSS and
also worth having around. It's pretty decent, as editors go. The visual
diff is quite handy. Windows only, though.http://notepad-plus-plus.org/

And thank the good people that created the vi plugin for Visual
Studio. It makes development in the IDE tolerable.
 
A

Andrew Smallshaw

But what happens when the code defines a variable two pages into a function,
but you happen to be reading some code using that same variable four pages
into the function! Where do you go to find the definition? At the start of a
function is usually a good place! You don't always know that a variable is
only used once.

And with blocks having their own scope (?) the same name can be used more
than once with different definitions; even more confusing.

That's precisely the whole point: if you declare a variable inside
a block you DO KNOW that it is only used there and if the identifier
appears elsewhere it must be referring to something else. There
are many times you want a local variable for a short amount of time
and that's it. If you declare the variable in the appropriate
block you don't need to mentally keep track of the variable either
before or after that block. Fewer variables to keep track of
generally means fewer corner cases, fewer uninitialised or outdated
variables, and fewer dangling pointers, whether they are still
relevant or not.

One fairly common idiom that comes to mind would be along the lines of:

if (some_condition()) {
int retval = operation(object);
free(object);
return retval;
}

Why have an extra variable hanging around a whole function for
something so trivial? What is more, a variable like that is easily
identified by the compiler as being short lived and can be optimised
as such - put into a register or whatever. It knows that it doesn't
need to preserve its value because you happened to re-use the same
variable for something else later in the function.
 
B

BartC

One fairly common idiom that comes to mind would be along the lines of:

if (some_condition()) {
int retval = operation(object);
free(object);
return retval;
}

In practice, you would define one 'retval' or 'temp' variable at the start,
and reuse it whenever the same construct occurs.

In the same way I might define int i,j,k; in preparation for any for-loops
there might be. Then there's one symbol saved in the for-loop construct,
which in C already needs a lot of syntax (a minimum of 13 symbols), which
would otherwise contribute little to a reader of the code (you can see
instantly that each for-loop uses an int loop index, but that's not exactly
news).
Why have an extra variable hanging around a whole function for
something so trivial? What is more, a variable like that is easily
identified by the compiler as being short lived and can be optimised
as such - put into a register or whatever. It knows that it doesn't
need to preserve its value because you happened to re-use the same
variable for something else later in the function.

That's a good point. Although you are then starting to do the compiler's
job. (Keeping creating new variables throughout the code is a bit like how
SSA works, where a new, unique variable is created for each assignment.)
 
I

Ian Collins

But what happens when the code defines a variable two pages into a function,
but you happen to be reading some code using that same variable four pages
into the function!

Then you (or the original authour) are doing something very very wrong.
Where do you go to find the definition? At the start of a
function is usually a good place! You don't always know that a variable is
only used once.

C is the only language I know that had (in the last century) such
restrictive declaration rules. You wouldn't see this argument on a
forum for another language. If old C's declaration rules were such a
good idea, why have thy been ignored by most (all?) subsequent languages?
 
N

Noob

BartC said:
In the same way I might define int i,j,k; in preparation for any for-loops
there might be. Then there's one symbol saved in the for-loop construct,
which in C already needs a lot of syntax (a minimum of 13 symbols), which
would otherwise contribute little to a reader of the code (you can see
instantly that each for-loop uses an int loop index, but that's not exactly
news).

In C99, one would (should) write:

for (int i = 0; i < N1; ++i)
for (int j = 0; j < N2; ++j)
for (int k = 0; k < N3; ++k)
do_whatever_with(i, j, k);
 
I

ImpalerCore

Then you (or the original authour) are doing something very very wrong.


C is the only language I know that had (in the last century) such
restrictive declaration rules.  You wouldn't see this argument on a
forum for another language.  If old C's declaration rules were such a
good idea, why have thy been ignored by most (all?) subsequent languages?

I struggle with this when writing libraries because there is a choice
between supporting the widest range of environments versus having the
flexibility to group variables closer to their scope. As of now, I'm
still (grudgingly) writing variables at the beginning of the block. I
don't think for short functions or small numbers of variables that it
detracts much from readability, but I do miss for loop initializer
declarations.

Best regards,
John D.
 
I

Ike Naar

In practice, you would define one 'retval' or 'temp' variable at the start,
and reuse it whenever the same construct occurs.

In the same way I might define int i,j,k; in preparation for any for-loops
there might be. Then there's one symbol saved in the for-loop construct,
which in C already needs a lot of syntax (a minimum of 13 symbols), which
would otherwise contribute little to a reader of the code (you can see
instantly that each for-loop uses an int loop index, but that's not exactly
news).

Why don't you go one step further and declare
retval, temp, i, j, and k as global variables?
 
P

Paul J Gans

Then you (or the original authour) are doing something very very wrong.
C is the only language I know that had (in the last century) such
restrictive declaration rules. You wouldn't see this argument on a
forum for another language. If old C's declaration rules were such a
good idea, why have thy been ignored by most (all?) subsequent languages?

I'd think the argument works the other way. Back when C was
new the other dominant language was FORTRAN. Later came both
Basic, Algol, and Cobol. All were strongly typed languages.

Of these only C survives to any major extent, proving, it seems
to me, that it was the most *successful* of these languages.
Indeed, it also shows that perhaps in spite of its strong typing,
it has held up under the barrage of "new" languages.
 
I

Ian Collins

I'd think the argument works the other way. Back when C was
new the other dominant language was FORTRAN. Later came both
Basic, Algol, and Cobol. All were strongly typed languages.

Of these only C survives to any major extent, proving, it seems
to me, that it was the most *successful* of these languages.
Indeed, it also shows that perhaps in spite of its strong typing,
it has held up under the barrage of "new" languages.

What has strong typing do do with where a variable is declared?
 
B

BartC

Why don't you go one step further and declare
retval, temp, i, j, and k as global variables?

Because it won't work?

Exactly the same 'i' could be in use simultaneously in different functions.

That's unlikely to be the case with a single local 'i' in a function.

But you can also go too far the other way, and end up with this (modified
from Noob's example):

for (int i = 0; i < N1; ++i)
for (int i = 0; i < N2; ++i)
for (int i = 0; i < N3; ++i)
do_whatever_with(i, i, i); /* ? */

BTW, when using a debugger on such a program (where there are several local
variables with the same name), how are they identified? 'The 'i' in the 2nd
block of that 3rd 'if' of that fourth loop'? (I'm implementing this sort of
stuff at the moment, and this anonymity bothers me.)
 
B

Ben Bacarisse

I've snipped all the context because I don't think you address the issue
where variables are declared. But I do want to comment...
I'd think the argument works the other way. Back when C was
new the other dominant language was FORTRAN. Later came both
Basic, Algol, and Cobol. All were strongly typed languages.

Cobol was massive long before C came along, and Algol dates from the
1950s. Basic is a little younger than Algol, but it was around in the
1960s and was riding a wave caused by the boom in microprocessors
(admittedly in a dizzying array of dialects) when most people started to
became aware of C.
Of these only C survives to any major extent, proving, it seems
to me, that it was the most *successful* of these languages.
Indeed, it also shows that perhaps in spite of its strong typing,
it has held up under the barrage of "new" languages.

I would not say that C has strong typing. It added typing to its
predecessor (B) but it did so in such a way that the types rules are
deliberately easy to break or circumvent.
 
L

Les Cargill

Ian said:
Then you (or the original authour) are doing something very very wrong.


C is the only language I know that had (in the last century) such
restrictive declaration rules. You wouldn't see this argument on a
forum for another language. If old C's declaration rules were such a
good idea, why have thy been ignored by most (all?) subsequent languages?

Probably because C left a suite of restrictions people targeted. To an
extent, defining a new language is a bit... odd. We have a bit
of a Tower of Babel problem as it is.
 

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

No members online now.

Forum statistics

Threads
474,079
Messages
2,570,574
Members
47,206
Latest member
Zenden

Latest Threads

Top