opinion wanted about global vars

C

Capstar

Hi,

I am working on an application, which will run embedded without an OS.
The app is build up out of a couple of well defined parts. At first I
wanted to keep those parts seperated and use opaque data types to
transfer information in between them.
At some stage I was stuck and needed to make a variable global, and I
also needed to make the struct declaration public to some other parts.

Looking through the code I found out that lots of functions, which were
intended to alter the data structure would contain only one or two
lines. So I wrote macros to speed things up.
Looking through the assembly I discovered that the compiler would leave
some function calls completely out because of the optimisation of the
code including the macro.

So now for my real question, what is your opinion on using global
variables/structures and macro's to access them in this sort of environment?
I normally try to avoid global variables as much as possible, but in
this case I see somereal advantages esspecially over the opaque data
approach.

Mark
 
T

Thomas Stegen

Capstar said:
now for my real question, what is your opinion on using global
variables/structures and macro's to access them in this sort of environment?
I normally try to avoid global variables as much as possible, but in
this case I see somereal advantages esspecially over the opaque data
approach.

(By global I mean a variable with indefinite scope and indefinite extent)
(Structured code is code that does not use any unconditional jumps and none
of the paths the code can take crosses over each other)

If the design turns out to be better, then use globals. Avoiding globals is
not
a goal in itself. The goal is to make better designs and more readable code.

It is the same thing with structured programming, it is not a goal in
itself.
If goto or break or continue makes your code better then you should use
them.
Not doing so is wrong. (or at least less good). I once read a comparison of
two functions representing the same abstraction, one using goto and one
without
goto. The conclusions was that the implementation was more or less
equivalent
because the function without goto was more complex and a bit harder to read
of
the two, the function with goto was bad because it used goto. That is just
idiotic.
Can't remember where that was though.

Situations where unstrucured code and globals are desireable are rare, but
not
unheard of. If you avoid them just on general principle then you are doing
something wrong. If you need globals, try to make them static, if that hurts
more
than it helps do not make them static.

Bad thing about globals is that there is a new potential side effect in all
functions that has access to that variable and that it might be more
difficult
to introduce threading in a program that uses them.

Just remember that avoiding goto and globals is not a goal in itself and
that
structured code is not a goal in itself.

Unless of course you are doing an academic exercise. (Not having a go at
those,
just saying that sometimes they become a goal in themselves).

I guess I am saying that the words "never" and "always" are always wrong in
software engineering. :p
 
?

=?iso-8859-1?Q?Juli=E1n?= Albo

Capstar escribió:
I am working on an application, which will run embedded without an OS.

Then, why you post in a group about programming for a concrete OS?

Regards.
 
J

Joona I Palaste

Julián Albo <[email protected]> scribbled the following
Capstar escribió:
Then, why you post in a group about programming for a concrete OS?

Why do YOU post in a group about programming, which does not have
anything to do with OSes?

--
/-- Joona Palaste ([email protected]) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"The day Microsoft makes something that doesn't suck is probably the day they
start making vacuum cleaners."
- Ernst Jan Plugge
 
E

E. Robert Tisdale

Capstar said:
I am working on an application, which will run embedded without an OS.
The application is build up out of a couple of well defined parts.
At first, I wanted to keep those parts separated
and use opaque data types to transfer information in between them.
At some stage, I was stuck and needed to make a variable global.

Really. Can you post some of the code
and explain to us why you thought you were "stuck"?
I also needed to make the struct declaration public
to some other parts.

Looking through the code I found out that lots of functions,
which were intended to alter the data structure
would contain only one or two lines.
So I wrote macros to speed things up.

Why didn't you use inline functions instead?
Looking through the assembly I discovered that
the compiler would leave some function calls completely out
because of the optimization of the code including the macro.

So now for my real question,
"What is your opinion on using global variables/structures and macro's
to access them in this sort of environment?"
I normally try to avoid global variables as much as possible
but, in this case, I see some real advantages
especially over the opaque data approach.

Global constants are good but you should avoid global variables.

Please post some simple examples so that
we can show you how to modify them to avoid the global variables
that you claim that you needed.
 
T

The Real OS/2 Guy

So now for my real question, what is your opinion on using global
variables/structures and macro's to access them in this sort of environment?
I normally try to avoid global variables as much as possible, but in
this case I see somereal advantages esspecially over the opaque data
approach.

Avoid globals wherever possible. But don't avoid global variables only
to avoid them!

In other words: Whenever possible concentrate all functionality to an
variable into one translation unit.

As this is not ever possible define a separate header that can be
included only in all the modules that need access to the variables and
another header that contains only the interfaces to the functions
designed to use from somewhere.

A translation unit that needs access to the internals of another
transation unit can include both header, the public one and the
internal one.

It lefts on you and your design to place the definitions on the
translation unit they belongs to and declarations (extern) on private
or public headers. As anything you publishes in an public header can
included anywhere it lefts on the discipline and the rules for the
whole team NOT to misuse this. But it is more save as to store
anything in one global header.

It lefts at least on you to find the right compromise.
 
J

Jack Klein

Hi,

I am working on an application, which will run embedded without an OS.
The app is build up out of a couple of well defined parts. At first I
wanted to keep those parts seperated and use opaque data types to
transfer information in between them.
At some stage I was stuck and needed to make a variable global, and I
also needed to make the struct declaration public to some other parts.

Looking through the code I found out that lots of functions, which were
intended to alter the data structure would contain only one or two
lines. So I wrote macros to speed things up.
Looking through the assembly I discovered that the compiler would leave
some function calls completely out because of the optimisation of the
code including the macro.

So now for my real question, what is your opinion on using global
variables/structures and macro's to access them in this sort of environment?
I normally try to avoid global variables as much as possible, but in
this case I see somereal advantages esspecially over the opaque data
approach.

Mark

I use the phrase "non local variables" (my invention) to refer to
variables defined at file scope, regardless of whether they have
internal or external linkage.

The biggest difficulties caused by the use of this type of variable
are, in my opinion, these two:

1. Accidental modification via name duplication.

2. Difficult to understand code due to such variables being modified
"behind the scenes" of code one is reading.

We have come up with rules for use of such objects in coding projects,
especially but not limited to those involving more than one
programmer.

Truly global variables are absolutely forbidden. Values which must be
used throughout a program need to belong to some specific code. If
the values must be read by a lot of different code, so much that "get"
calls become a burden, put them all in a structure and pass around a
const qualified pointer to it to functions that need the values.

If you have program-wide data that must be changed very often and from
all over the code, redesign right now.

The next step is to minimize the accessibility of all non-locals.
Modularize your code. When a variable needs to be shared between a
few related functions that fit comfortably in a single source file,
define it there with the static keyword.

Otherwise break the code into functional modules (example, file i/o,
printing, spell checking, whatever). Each module goes into its own
directory. Non-locals needed by various functions in different source
files within the modules is prefixed with a module specific prefix to
and declared in a header located in the module's directory, not
allowed to be included by source files outside the directory.

The module-specific prefix prevents global name provision, and
simulates multiple external namespaces such as the C++ namespace
feature provides. So you can have PR_lines_per_page in your print
module that can't possible clash with anything defined in your file
i/o module, where everything starts with FIO_. This is useful for
functions with external linkage as well.

Finally the important restriction on non-local variables. With a few
trivial exceptions, we require the following:

If a function accesses the value of a non-local variable, that value
will remain invariant for each execution of that function other than
for visible modifications in that function.

This last one has saved a lot of grief. It initially came about
because of a very poorly coded state machine implementation, like
this:

enum state { STATE0, STATE1, STATE2, STATE3 } the_state;

void some_func(void)
{
if (STATE0 == state)
func_1();

if (STATE1 == state)
func_2();

if (STATE2 == state)
func_3();

if (STATE3 == state)
func_4();
}

When questioned in a code inspection as to why either a switch
statement or an if..else if...else if...else structure was not used,
the author revealed that some (but not all) of the called functions
might modify the state variable. In some cases, to more than one
possible value. So a single call of the function could result in
calling at least one, but sometimes two or three of the different
functions.

Hence the insistence on visible changes to non-locals if they changed
during the execution of a function.

Even something like this:

switch (state)
{
case STATE0:
func_1();
func_other();
func_yes_another();
break;

/* etc. */
}

....can be made much more readable and maintainable by changing the
called functions to return a new state to the caller...

switch (state)
{
case STATE0:
func_1();
func_other();
state = func_yet_another();
break;
/* etc. */
}

If the day ever comes that I need to understand and modify this
function, written by somebody else, or even by me years later, I can
see at a glance which functions might actually decide on a state
change and which cannot.

As for the trivial exception, something to allow for debugging like
this:

void change_state(state_type new_state)
{
#if DEBUGGING
printf("state change from %d to %d\n", state, new_state);
#endif
state = new_state;
}

Now:

switch (state)
{
case STATE0:
func_1();
func_other();
change_state(func_yet_another());
break;
/* etc. */
}

....is considered to meet the requirements.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
?

=?iso-8859-1?Q?Andr=E9_P=F6nitz?=

In comp.os.linux.development.apps Capstar said:
Looking through the code I found out that lots of functions, which were
intended to alter the data structure would contain only one or two
lines. So I wrote macros to speed things up.

Bad move. Why don't you use inline function if you really need to?
Looking through the assembly I discovered that the compiler would
leave some function calls completely out because of the optimisation
of the code including the macro.

So now for my real question, what is your opinion on using global
variables/structures and macro's to access them in this sort of
environment?

Generally spoken: global variables are bad, macros are not better.
There are certainly occasions, where both are justified, but these are
rare. It's certainly not the common case.

Andre'
 
P

pete

André Pönitz said:
Bad move. Why don't you use inline function if you really need to?


Generally spoken: global variables are bad, macros are not better.
There are certainly occasions, where both are justified, but these are
rare. It's certainly not the common case.

I think that if a macro doesn't use any variables,
except those which are passed in as arguments,
then using the macro shouldn't become complicated.

#define SWAP(A, B, T) ((void)((T) = *(A), *(A) = *(B), *(B) = (T)))
 
M

Martijn

This is an old article from usenet which I had decided to store on my HD for
some reason. It makes for pretty fun reading and it perfectly illustrates
your point. It was originally posted by Wim Libaers
(http://groups.google.com/groups?q=g:thl170339318d&selm=clcm-20020321-0051%4
0plethora.net , this version is slightly altered at the beginning)

Here are some questions on ANSI C...


Great! We all love interesting questions, especially such thought-
provoking ones!

1.
Describe the process you would use to replace a do/while loop with an
equivalent while loop.


It involves a clever technique called "editing source code". Don't tell
anyone I told you this, it's a secret!

Suppose you have been told that you must remove a while loop and
replace it with a do/while.

What additional control structure would you need to use and how would
you use it to ensure that the resulting program behaves exactly as the
original?


Why would you change the program if you wanted it to behave in exactly the
same way? Wouldn't it be better if it behaved differently? Anyway,

goto bottom;
do
{
/* any statements from inside the while loop go here */
bottom:
} while (condition);

Note that this uses a goto, which is very bad, EVIL STUFF! There is a much
better way, extremely clean, top quality code. It's a classic, too,
although it was originally used for different reasons. Credit goes to Tom
Duff.

switch (1)
{
do
{
/* loop contents here */
case 1: ;
} while (a);
}

It should be obvious immediately why this is superior compered to the
previous case. Superior to the while loop even, because we are using more
structured programming statements, so the code is increasingly getting
more and more exceedingly structured.

A criticism of the break statement and the continue statement is that
each is unstructured.


Exactly! Even worse for goto! That's why I used the structured switch
statement above.

Actually break statements and continue statements can always be
replaced by structured statements, although doing so can be awkward.
Describe in general how you would remove any break statement from a
loop in a program and replace that statement with some structure
equivalent.


Easy one. Put extra conditions in the loop condition statement for every
break to be replaced, and add if statements with the opposite condition of
the one that would have triggered the break, and enclosing everything that
follows. To prevent side-effects (why would you want to do that?) use a
flag instead of repeating the condition. Don't alter the flag anywhere
else. Do note that in some cases, a bit of extra structure is required.
For example, in replacing this one:

while (a--)
{
if (1)
{
if (c++) break;
b--;
}
b--;
}

A clean solution would be (d being the flag):

while (d && a--)
{
if (1)
{
if (d && c++) d--;
if (d)
{
b--;
}
}
if (d)
{
b--;
}
}

Clearly, the removal of the break has simplified this code enormously, and
made maintenance much easier. And added twice as much structure as in a
simple case. So, you see that a deeply nested break provides more
opportunities for beautifying code with structure until it's so structured
it almost makes your eyes hurt. Nothing is more structured than if
statements structuredly nested, so the more nested (or stacked) if
statements the more structured your code becomes.
By the way, the (d && a--) can be made nicer by using (d ? a-- : d)
instead. Same for the other one!

Describe in general how you would remove any continue statement from a
loop in a program and replace that statement with some structured
equivalent.


As above, but omitting the flag check in the condition statement of the
while loop.

Describe in general how you would remove break statements from a
switch structure and replace them with structured equivalents.


So, for example, you have:
switch (s)
{
case 1: a++; break;
case 2: b++; break;
case 3: c++; break;
default: s++;
}

Again, if is your friend!

switch (s)
{
case 1: a++;
if(0)
{
case 2: b++;
if(0)
{
case 3: c++;
if(0)
{
default: s++;
}
}
}
}


Isn't that beautiful? Not perfect though, the compiler gave me some
warnings about conditions always being false. To clarify the code and
remove the warnings, the zero in the if can be replaced by an int you give
the value zero before the loop.
A much more interesting solution is this:


switch (s)
{
case 1: if (s==1) a++;
case 2: if (s==2) b++;
case 3: if (s==3) c++;
default: if (s-1?s-2?s-3?1:0:0:0) s++;
}

Don't you just love that?
 
?

=?iso-8859-1?Q?Andr=E9_P=F6nitz?=

In comp.os.linux.development.apps pete said:
I think that if a macro doesn't use any variables,
except those which are passed in as arguments,
then using the macro shouldn't become complicated.

#define SWAP(A, B, T) ((void)((T) = *(A), *(A) = *(B), *(B) = (T)))

Big fun with

SWAP(++A, B, T)

and similar.

If an inline function can do the job, prefer it over macros.

Andre'
 
B

Bob R

Martijn wrote in message said:
<snip>
switch (s){
case 1: if (s==1) a++;
case 2: if (s==2) b++;
case 3: if (s==3) c++;
default: if (s-1?s-2?s-3?1:0:0:0) s++;
}

** Don't you just love that? **

Nooo. I'm a C++ newbie and you just made my head hurt!! <G>

Anybody got an IEEE/ISO asperin?
--
Bob R
POVrookie
--
MinGW (GNU compiler): http://www.mingw.com/
Dev-C++ IDE: http://www.bloodshed.net/
V IDE & V GUI: http://www.objectcentral.com/
POVray: http://www.povray.org/
Good C++ book: http://www.mindview.net/Books
alt.comp.lang.learn.c-c++: ftp://snurse-l.org/pub/acllc-c++/faq
 

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
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top