Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > global/static variables & loops

Reply
Thread Tools

global/static variables & loops

 
 
Malcolm McLean
Guest
Posts: n/a
 
      02-15-2012
On Feb 15, 2:55*pm, Anders Wegge Keller <(E-Mail Removed)> wrote:
> Nick Keighley <(E-Mail Removed)> writes:
> > Oh, and why does your progranm have global variables in the first
> > place?

>
> *Can you give an example of a non-trivial program, that has no global
> state in any way?
>

Ultimately you need some way of doing IO, which means communicating
with some physical device, which is likely to mean memory mapping at a
low level and thus global control variables at a high level.

But if we can assume that fopen() and printf() work by magic, then
it's possible to write the program without any global state. Trivally,
you could declare a struct myglobals and pass it to every function in
the call tree. But often you don't need to do this, the program it's
just natural to declare the few persistent state varibales as local to
main and pass them as parameters.

The program I'm currently working on has no globals or statics, for
example. It takes quite a rich set of command line arguments friom the
user, ands so it calls a general purpose "options parser" which stores
the command line in a temporary structure, and allows queries. Then it
destroys that structure after extracting about a dozen parameter
variables. It then loads a csv file into a CSV structure, extracts two
columns of data as specified by the user, and destoys the CSV
structure. The columns are converted to a data density map, using a
palette specified byt eh user, and then written out as a JPEG.

So no globals required. It does have state in main which persists for
the life of the program, however.
--
Coming soon: the data density program
http://www.malcolmmclean.site11.com/www

 
Reply With Quote
 
 
 
 
Anders Wegge Keller
Guest
Posts: n/a
 
      02-15-2012
Malcolm McLean <(E-Mail Removed)> writes:

> But if we can assume that fopen() and printf() work by magic, then
> it's possible to write the program without any global state. Trivally,
> you could declare a struct myglobals and pass it to every function in
> the call tree.


That is global state in my book.

> But often you don't need to do this, the program it's just natural
> to declare the few persistent state varibales as local to main and
> pass them as parameters.


As is this, if you need to propagate the same value unchanged down
the call tree from main().

My point is that no matter how you try to hide it, whether it's to
get rid of global variables, just because they are baaad, or if you
actually need to do something in a smarter way, there is hardly a
program that hasn't got a global state. And in that case, I fail to
see why the program would be any worse, by actually admitting the
fact.

--
/Wegge

Leder efter redundant peering af dk.*,linux.debian.*
 
Reply With Quote
 
 
 
 
James Kuyper
Guest
Posts: n/a
 
      02-15-2012
On 02/15/2012 12:25 PM, Anders Wegge Keller wrote:
> Malcolm McLean <(E-Mail Removed)> writes:
>
>> But if we can assume that fopen() and printf() work by magic, then
>> it's possible to write the program without any global state. Trivally,
>> you could declare a struct myglobals and pass it to every function in
>> the call tree.

>
> That is global state in my book.


If that counts as global state, then storing global state in global
variables is clearly not necessary.

....
> My point is that no matter how you try to hide it, whether it's to
> get rid of global variables, just because they are baaad, ...


Your use of "just" and "baaad" implies that you think that the idea that
globals are bad is an unjustified prejudice, rather than the
well-justified judgment that it actually is. Are you actually unaware of
the problems that they can cause?

> ... or if you
> actually need to do something in a smarter way, there is hardly a
> program that hasn't got a global state. And in that case, I fail to
> see why the program would be any worse, by actually admitting the
> fact.

n
The key problem with global variables is visibility; by being visible
everywhere, they can be affected by anything, which can make it
difficult to determine what part of the program caused those variables
to have their current value, or what part had it's behavior affected by
the value. Variables which are local to main() and are passed by a
pointer to subroutines need not be passed to all subroutines, but only
the ones that actually need to have access to those variables, and that
could be a different set of subroutines for different variables. Making
information available to a subroutine only on a "need to know" basis is
good software design. It can be overdone, but that's seldom a real-world
problem.
--
James Kuyper
 
Reply With Quote
 
Malcolm McLean
Guest
Posts: n/a
 
      02-15-2012
On Feb 15, 6:25*pm, James Kuyper <(E-Mail Removed)> wrote:
> On 02/15/2012 12:25 PM, Anders Wegge Keller wrote:
>
> > Malcolm McLean <(E-Mail Removed)> writes:

>
> >> But if we can assume that fopen() and printf() work by magic, then
> >> it's possible to write the program without any global state. Trivally,
> >> you could declare a struct myglobals and pass it to every function in
> >> the call tree.

>
> > *That is global state in my book.

>
> If that counts as global state, then storing global state in global
> variables is clearly not necessary.
>

If you take a program, list every global variable, pack them into a
structure, and then pass a pointer to the structure to every function
in the call tree, you aren't really achieving much. However you are
making it easier for the program to accept two states (think a GUI
program going from a single document model to a tabbed interface
allowing multiple documents.
>
> The key problem with global variables is visibility; by being visible
> everywhere,
>

The other problem is portability and testing.

Lets say we do this

EMPLOYEE myemployees[100];
int Nemployees;
double averagesalary()
{
/* step through the employee array calculating average salary */
}

Now it's hard to test. We have to set up the employees structure to
check it.

Let's say we do this instead

double average(void *data, int offset, int stride, int N)

it takes a bit more writing. But once we've done, we can copy and
paste and use the code in many different applications, which might not
have anything else in common with each other. And we're much more
likely to document what happens when N == 0, which is where the bug is
likely to creep in, or what happens when we get Mr Fred the Shred and
salary goes to DBL_MAX (apologies to American readers who won't
understand this reference).

--
Visit my website. Data density program coming soon
http://www.malcommclean.site11.com/www
 
Reply With Quote
 
Anders Wegge Keller
Guest
Posts: n/a
 
      02-15-2012
James Kuyper <(E-Mail Removed)> writes:

> On 02/15/2012 12:25 PM, Anders Wegge Keller wrote:


>> That is global state in my book.


> If that counts as global state, then storing global state in global
> variables is clearly not necessary.


No, but when the effect is the same anyway, why add another level of
complexity?

>> My point is that no matter how you try to hide it, whether it's to
>> get rid of global variables, just because they are baaad, ...


> Your use of "just" and "baaad" implies that you think that the idea
> that globals are bad is an unjustified prejudice,


It very often is an unreflected, almost religious observance. Just
like "gotos are bad". The next thing you see, is people mechanically
replacing a global variable with a static, and adding getters and
setters because the same state is still needed globally.

> rather than the well-justified judgment that it actually is.


If it quacks like a duck, walks like a duck and swims like a duck, it
probably is a duck, no matter how you dress it up.

> Are you actually unaware of the problems that they can cause?


If people write bad code, they will get into trouble, no matter what
paradigm they adhere to. I can think of lots of ways a program can
become difficult to manage by doing something stupid with a
global. But that is not exclusive to that style.

>> ... or if you actually need to do something in a smarter way, there
>> is hardly a program that hasn't got a global state. And in that
>> case, I fail to see why the program would be any worse, by actually
>> admitting the fact.


> The key problem with global variables is visibility; by being
> visible everywhere, they can be affected by anything, which can make
> it difficult to determine what part of the program caused those
> variables to have their current value, or what part had it's
> behavior affected by the value.


Scratch the getter/setter pattern, and the global struct pointer
that's passed down the call tree then. *OR* prototype the darn things
as const outside the translation unit that actually has to modify
them, and see where the compiler complains. (And remember to remove
the const prototype afterwards, unless you want to see some
spectacular failures

> Variables which are local to main() and are passed by a
> pointer to subroutines need not be passed to all subroutines, but only
> the ones that actually need to have access to those variables, and that
> could be a different set of subroutines for different variables.


Unless you have a very limited state space, that will lead to some
very convoluted and error-prone code.

> Making information available to a subroutine only on a "need to
> know" basis is good software design. It can be overdone, but that's
> seldom a real-world problem.


You should try to do real-time machine control with 10-15
co-concurrent tasks running on a 80186 platform, where each individual
thread has a stack in the range 128 to 256 bytes, and avoid overdoing
need-to-know I'm in the 0.1%, where overdoing things are a
real-world problem.

--
/Wegge

Leder efter redundant peering af dk.*,linux.debian.*
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      02-15-2012
On 02/15/2012 01:51 PM, Malcolm McLean wrote:
....
> If you take a program, list every global variable, pack them into a
> structure, and then pass a pointer to the structure to every function
> in the call tree, you aren't really achieving much.


Yes, that's right. I wouldn't pass the whole set of variables in main()
to each subroutine of main(), but only the parts needed by that subroutine.
--
James Kuyper
 
Reply With Quote
 
Anders Wegge Keller
Guest
Posts: n/a
 
      02-15-2012
Malcolm McLean <(E-Mail Removed)> writes:

> Lets say we do this
>
> EMPLOYEE myemployees[100];
> int Nemployees;
> double averagesalary()
> {
> /* step through the employee array calculating average salary */
> }


I don't know if I've made myself clear previously, but I'm in this
thread, asking about programs having *NO GLOBAL STATE AT ALL*.

No debug levels.
No log destinations.
No file handles.
No nothing.

I have no trouble seing why *DATA* should not be globally visible,
unless there are some very good reasons for them being so, like my
co-existing embedded threads, mentioned elsewhere. But that is beyond
the express negative I questioned earlier.

--
/Wegge

Leder efter redundant peering af dk.*,linux.debian.*
 
Reply With Quote
 
Anders Wegge Keller
Guest
Posts: n/a
 
      02-15-2012
James Kuyper <(E-Mail Removed)> writes:

> On 02/15/2012 02:30 PM, Anders Wegge Keller wrote:


>> If it quacks like a duck, walks like a duck and swims like a duck, it
>> probably is a duck, no matter how you dress it up.

>
> Well, that works both ways - labeling it a prejudice doesn't make it
> cease to be a well-justified judgment.


Yoy have missed the point. I'm talking about cases like

int debug_level;

versus:

static int debug_level
int get_debug_level(void) { return debug_level; }
void set_debug_level(int lvl) { debug_level = lvl; }

I'm not trying to justify "All data should be global", as you seem to
imply. I'm questioning "No data should be global". There is a world
between those two statements.

>> Scratch the getter/setter pattern, and the global struct pointer
>> that's passed down the call tree then. *OR* prototype the darn things
>> as const outside the translation unit that actually has to modify
>> them, and see where the compiler complains. (And remember to remove
>> the const prototype afterwards, unless you want to see some
>> spectacular failures


> I'm not sure what any of that word salad has to do with what I was
> talking about. Can you re-write it to make the relevance clearer?


If my explanation above doesn't make it clearer, please ask
again. But I think we have two very different opinions about what
"state" actually means at present.

>> Unless you have a very limited state space, that will lead to some
>> very convoluted and error-prone code.


> Not in my experience.


Try implementing GNU ls without globals. I know that the whole lot
are statics, since the code is in just one TU, but imagine something
of a similar magnitude then. The first few levels of functions will
have prototypes of several pages.

>> You should try to do real-time machine control with 10-15
>> co-concurrent tasks running on a 80186 platform, where each
>> individual thread has a stack in the range 128 to 256 bytes, and
>> avoid overdoing need-to-know I'm in the 0.1%, where overdoing
>> things are a real-world problem.


> Limited stack space is something I've little recent experience with,
> but I agree that it's an excellent reason to avoid using the stack;
> in extreme cases, even passing pointers on the stack becomes
> problematic - but you should rarely need to go all the way to global
> visibility to avoid that problem. You have a greater need to use
> objects with static storage duration than I do, but you don't have
> to make every single one of them globally visible. I've a number of
> such objects in my own code. Most of them have block scope, a few
> have file scope - but none has external linkage.


When data is shared between several threads, and each thread live in
its own translation unit, that cannot be helped. The central part is
an array-esque (80186 memory model limitations) representation of
system state. Most manipulation happens through a set of state-event
machines, each doing their part.

And mind, this is hardware that was state of the art in the late
1980's, and we have been stuck on that ever since, because it works
too good to warrant a major architecture rewrite.

--
/Wegge

Leder efter redundant peering af dk.*,linux.debian.*
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      02-15-2012
On 02/15/2012 03:30 PM, Anders Wegge Keller wrote:
> James Kuyper <(E-Mail Removed)> writes:
>
>> On 02/15/2012 02:30 PM, Anders Wegge Keller wrote:

>
>>> If it quacks like a duck, walks like a duck and swims like a duck, it
>>> probably is a duck, no matter how you dress it up.

>>
>> Well, that works both ways - labeling it a prejudice doesn't make it
>> cease to be a well-justified judgment.

>
> Yoy have missed the point. I'm talking about cases like
>
> int debug_level;
>
> versus:
>
> static int debug_level
> int get_debug_level(void) { return debug_level; }
> void set_debug_level(int lvl) { debug_level = lvl; }


That's just a global dressed up in fancy clothes. It has all of the
disadvantages of a global, while being unnecessarily more complicated
than defining a global. If the setter function at least implemented some
kind of validity test on the new level, the example would make a little
more sense, but I had not considered that you were arguing against this
kind of idea.

> I'm not trying to justify "All data should be global", as you seem to
> imply. I'm questioning "No data should be global". There is a world
> between those two statements.


I'd argue for "little, if any, data should be global". The only objects
that should have external linkage are those which will be used almost
everywhere in a program, and in my experience there aren't many of
those. If there are, poor design is usually to blame. To take your
example, I could quite easily imagine wanting to have different debug
levels in different parts of the program, which would make a single
global debug level inappropriate.

...
> Try implementing GNU ls without globals. I know that the whole lot
> are statics, since the code is in just one TU, but imagine something
> of a similar magnitude then. The first few levels of functions will
> have prototypes of several pages.


I don't have time to implement the entirety of ls; if the sheer
complexity of ls is your point, then I won't be able to address it
directly. If there's some particular feature of ls that you think
requires use of globals, I could possibly spare time to implement a
simplified version providing only that feature.
--
James Kuyper
 
Reply With Quote
 
Anders Wegge Keller
Guest
Posts: n/a
 
      02-15-2012
James Kuyper <(E-Mail Removed)> writes:

> On 02/15/2012 03:30 PM, Anders Wegge Keller wrote:


> That's just a global dressed up in fancy clothes. It has all of the
> disadvantages of a global, while being unnecessarily more complicated
> than defining a global.


I'm happy to see that I managed to make myself clear. But sadly, I've
seen text books and style guides that advocates exactly this pattern.

...

>> I'm not trying to justify "All data should be global", as you seem to
>> imply. I'm questioning "No data should be global". There is a world
>> between those two statements.


> I'd argue for "little, if any, data should be global". The only
> objects that should have external linkage are those which will be
> used almost everywhere in a program, and in my experience there
> aren't many of those.


Apart from our embedded code, most of what I write for a living are
event-driven processes, that do a lot of IPC with each other. That
gives quite a lot of state, that either has to be a global, or be
dressed up as something else with the same properties, as the naive
example from last post.

> If there are, poor design is usually to blame. To take your example,
> I could quite easily imagine wanting to have different debug levels
> in different parts of the program, which would make a single global
> debug level inappropriate.


Actually you have CHAR_BIT * (sizeof(int)/sizeof(char)) debug
masks. If that isn't enough, the process should probably be split into
two or more parts that are a bit more focused.

>> Try implementing GNU ls without globals. I know that the whole lot
>> are statics, since the code is in just one TU, but imagine something
>> of a similar magnitude then. The first few levels of functions will
>> have prototypes of several pages.


> I don't have time to implement the entirety of ls; if the sheer
> complexity of ls is your point, then I won't be able to address it
> directly.


I stated ls as an antithesis to

"Variables which are local to main() and are passed by a pointer
to subroutines need not be passed to all subroutines, but only
the ones that actually need to have access to those variables, and
that could be a different set of subroutines for different
variables."

Dividing the whole set of options into structs that are passed on a
stict "need to access"-basis for each individual function called from
main() will in effect lead to passing almost any command line option
as a separate argument down the call graph from main().

--
/Wegge

Leder efter redundant peering af dk.*,linux.debian.*
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Put variables into member variables or function variables? tjumail@gmail.com C++ 9 03-23-2008 04:03 PM
For Loops and Variables Jason Cavett Java 18 04-10-2007 02:38 PM
Loops with loops using html-template Me Perl Misc 2 01-12-2006 05:07 PM
float variables in loops vijay C Programming 8 05-05-2005 08:40 AM
declaring variables inside for loops Grey Plastic C++ 3 08-10-2004 10:40 AM



Advertisments