C: Global Variables versus Parameters

Nibbie
Posts: 4
Joined: 2010.01
Post: #1
I am reading "Learn C on the Mac" by Dave Mark, which I am finding to be a good book. However, Mark states that global variables are to be avoided if possible, and that it is better to use parameters. Is this correct? His book doesn't really explain why they should be avoided, other than saying that "they do save time but at the cost of proper program design."

Global variables seem a lot easier to grasp and use than parameters. Is using global variables really considered improper program design? Why?
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #2
Generally speaking, if you have a function that calls another and it's affecting a variable that's only used in that function, yes, don't use a global for that.

Yes, you should avoid using globals if you really don't need to. Knowing when to use one or not takes experience.

Ahem... That said, personally I find absolutely nothing wrong with using globals whenever I darn-well want to!

One thing you will want to do though is distinguish between globals that are available anywhere in the program, or globals that are only available within the scope of that source file. The reason you want to keep your globals within the scope of that file is because it's easy to forget that you used a variable name in one file and then tried to use it again for something else in another file. The way you keep the global local to that file is by simply prefixing the declaration with the keyword, static. Example:

static int gMyGlobal;

It's a great habit to get into so you can keep your code more modular and easy to deal with.

So, with all that said, do be aware that over-use of global variables is considered "bad form" by many. It's also a source of poor performance in some cases because the global has to be loaded, whereas if you can keep a variable local it can be stored in a register. Those performance details aren't really all that important to know as you're learning, but just something to keep in mind.

One tip I would highly recommend (even insist) is that when you create a global variable it is an absolute must that it be named in such a way as to make it clear what it is. If you can't do that, at least be sure to write a good comment next to it where you declare it to describe what it's for. Local variables often document themselves, just by what they're used for in a particular function, but globals, being global in scope, don't always have that context to help hint at what they're for.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #3
Two more things:

1) You'll find that when you want to re-use a function in some other program, it's a lot easier to cut and paste it if all you need to do is the function. If it requires a global variable with it to use it, then you have to hunt down the variable's declaration and copy-paste that too. So in this sense, using parameters is definitely more convenient.

2) It's a nice touch, if you can, to prefix your global variables with "g", so that when you're reading your code later (or someone else is reading it!), you'll instantly recognize it as a global. Example (as above):

int gMyGlobal;

as opposed to just:

int myGlobal;
Quote this message in a reply
Member
Posts: 194
Joined: 2009.02
Post: #4
I remember asking the exact same question when I was learning C. I agree with with everything AnotherJake said, and would just suggest a few more things you could do if you wanted.

Say you have a source file called main_menu, and in that file you have a global variable, g_is_main_menu_open, obviously functions outside of the source will want to query it so it's helpful to create an accessor function like this:

BOOL is_main_menu_open() {
return g_is_main_menu_open;
}

When you iterate through a list of game entities(and eventually you will), you may want want to use pointer parameters, rather than passing indices, it's quicker, more elegant, and makes your code easier to read.

obj_type obj_list[MAX_OBJS];

obj_type* get_obj( int index )
{
return &obj_list[index];
}

void update_obj_ai( obj_type* obj )
{
.....
}
void update_obj_graphics( obj_type* obj )
{
.....
}

void update_obj( obj_type* obj)
{
update_obj_graphics( obj );
udate_obj_ai(obj);
}

void update_obj_list()
{
for (i=0;i<MAX_OBJS;i++)
update_object( get_obj(i) );
}
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #5
NelsonMandella Wrote:Say you have a source file called main_menu, and in that file you have a global variable, g_is_main_menu_open, obviously functions outside of the source will want to query it so it's helpful to create an accessor function like this:

BOOL is_main_menu_open() {
return g_is_main_menu_open;
}

When you iterate through a list of game entities(and eventually you will), you may want want to use pointer parameters, rather than passing indices, it's quicker, more elegant, and makes your code easier to read.
...

This is where it gets subjective and takes experience, and is kind of the "art" of C programming. Sometimes I prefer to use an accessor to make things cleaner, but sometimes I just go bare-bones and access the global directly from the other file to make things cleaner. One thing I will say that I've learned about C over the years: try to listen carefully to what everybody says and then disregard them and do whatever you want. Rebellion is liberating! Ninja
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #6
I'd put it this way:

Globals are available, and thus, very probably, also used everywhere in the program. This means that they are accessed and written to from many places. If you want to implement, say, checking that you never write -1 into gMySupervar, you have to implement this check everywhere. If you forget to do that in SupervillianDoStuff(), you just introduced a bug by *not* changing code.

And that's bitrot.

If you need global state, which you most likely do (even OOP concepts like singletons are just globals in reality), at least use accessor functions, in which you can implement sanity checks, or debug output.

Of course, designing things in such a way that you don't need global state at all would probably get you maximum points for style, but sometimes it's just not worth the hassle, as for simple things, the boilerplate code you have to add for proper encapsulation can take more time than writing actual functionality. However, as a program evolves, there will most likely come a point at which you should make the switch to keep the code sane.

And even though I wanted this post to have only a single paragraph, I also gotta say that a variable local to a module, eg prefixed with "static", is usually ok. As long as it is relevant to a large number of functions in a module.
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #7
To expand on what DoG said. It's about being able to debug code too.

Again with the example of the variable that should never be -1. It's easy enough to say that, but hard to enforce as DoG said. Now, lets say your program is crashing because the value is -1:

As a global variable, somewhere in your program you are writing myGloblal = (a - b)/c into the variable. Not exactly obvious that it could actually be -1 given the right a, b, and c. Then at some other point in the program you are reading the value back and crashing because you are trying to get the -1 item out of an array or something like that. Now you have to find all the places that can write into that variable and figure out which of them is writing -1 into it.

If it was passed as a parameter to a function when the program crashed, you would be able to open the program up in your debugger and see which function passed -1 to it and where it got it -1 from. This can make it much easier to debug your programs.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Member
Posts: 194
Joined: 2009.02
Post: #8
C programs can become very complex and difficult to manage once they reach anywhere from approximately 10k to 20k lines of code. Modular code helps to mitigate this complexity, but it can also add complexity to what would be a short, simple program.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #9
NelsonMandella Wrote:C programs can become very complex and difficult to manage once they reach anywhere from approximately 10k to 20k lines of code. Modular code helps to mitigate this complexity, but it can also add complexity to what would be a short, simple program.

Yeah, that's pretty well put.

The best way to learn when and how to use globals is experience. For small programs, like say less than 10k lines of code, accessors are probably just getting in the way of getting the program done. Larger than that and using techniques for modularity (and debugging as DoG and Skorche pointed out) definitely start coming into play.

I will add this: As you are learning, I wouldn't worry toooo much about whether you're using globals or not, or how you specifically use them. As you start to become familiar with the language it does become more obvious what globals and parameters are really useful for.
Quote this message in a reply
Member
Posts: 749
Joined: 2003.01
Post: #10
For short & simple programs you can actually not use any functions at all (keep everything in main).

Once you understand the power of functions you'll understand why passing stuff as parameter is often better.

©h€ck øut µy stuƒƒ åt ragdollsoft.com
New game in development Rubber Ninjas - Mac Games Downloads
Quote this message in a reply
Nibbie
Posts: 4
Joined: 2010.01
Post: #11
Thanks for all of your replies, all of them are very helpful and informative. Much appreciated.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Accessing an inherited class's variables Tobs_ 22 9,123 Feb 28, 2007 05:26 PM
Last Post: mac_girl
  Problems with variables in Obj-C vnvrymdreglage 16 6,497 Oct 2, 2006 10:19 PM
Last Post: vnvrymdreglage
  Should global variables be pointers or full objects? ia3n_g 1 2,314 Aug 4, 2006 05:53 PM
Last Post: OneSadCookie
  where do global variables fall into the memory type? WhatMeWorry 3 2,768 Jun 5, 2006 02:45 PM
Last Post: OneSadCookie
  Arrays or variables containing executable functions Jones 4 4,389 Jun 2, 2006 08:35 AM
Last Post: Zekaric