Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

extern for global variable: C Question

5 views
Skip to first unread message

Robby

unread,
Dec 18, 2009, 1:07:01 PM12/18/09
to
Hello,

I have asked this question in a previous post. I don't mean to double post,
but I would simply like to ask the same question in a more direct manner.

Please consider these .c modules:

=====================KERNEL.h
extern long MQ[];

=====================KERNEL.c
long MQ[10] = {1,2,3,4,5,6,7,8,9,0}; // <<< at top of a particular .c
file!

=====================API.c
#include KERNEL.h // <<< include KERNEL.h header in all .c files that
need MQ[]

void API_InsertMessage(enum enumKM m)
{ MQ[0] = m; }
===========================

Objective:
The data in the MQ array has to be accessible and available in many
functions of several .c files, and therefore should appear to have global
scope.

Resolution:
As shown in code above, I declared an array as "extern" and then defined it
in one .c file and where ever other .c files require access to MQ[], I have
to include the KERNEL.h file. Is this an okay practice to do with all other
global variables, arrays and arrays of structures?

P.S. I am only asking this to assure that I apply the same coding habits for
the rest of my global variables.

In all sincereity, thanks all for any feedback!

--
Best regards
Roberto

David Lowndes

unread,
Dec 18, 2009, 1:34:12 PM12/18/09
to
>As shown in code above, I declared an array as "extern" and then defined it
>in one .c file and where ever other .c files require access to MQ[], I have
>to include the KERNEL.h file. Is this an okay practice to do with all other
>global variables, arrays and arrays of structures?

Yes.

Dave

Robby

unread,
Dec 18, 2009, 2:34:01 PM12/18/09
to
Thank you Dave!

--
Best regards
Roberto


"David Lowndes" wrote:

> .
>

mzdude

unread,
Dec 18, 2009, 4:54:21 PM12/18/09
to
On Dec 18, 1:07 pm, Robby <Ro...@discussions.microsoft.com> wrote:
<snip>

> Resolution:
> As shown in code above, I declared an array as "extern" and then defined it
> in one .c file and where ever other .c files require access to MQ[], I have
> to include the KERNEL.h file. Is this an okay practice to do with all other
> global variables, arrays and arrays of structures?
>
> P.S. I am only asking this to assure that I apply the same coding habits for
> the rest of my global variables.
>

Having been bitten by global vars more than once in my life time, I
would do something like

=== Kernal.h =====
long GetMessage(int msgIndex );
void SetMessage(int msgIndex, long message );

==== Kernal.c ===
static long MQ[10] = {1,2,3,4,5,6,7,8,9,0};

long GetMessage(int msgIndex)
{ return MQ[msgIndex]; } // could add range check to index

void SetMessage(int msgIndex, long message)
{ MQ[msgIndex] = message; }


Just my preference.

==== Api.c ====
#include "Kernal.h"

void API_InsertMessage(enum enumKM m)
{ SetMessage(0, m); }


Now if you ever have to track down message changes, you
have a single function in Kernal.c to set break points in,
or add logging functions too.

Barry Schwarz

unread,
Dec 19, 2009, 3:58:11 AM12/19/09
to

While this is obviously the right (tm) way to define a global variable
exactly once and declare it extern everywhere it is needed, it begs
the question of whether global variables are the right choice. Since
they have a tendency to confound debugging, there is a school of
thought that strongly recommends passing the array as an argument to
those functions that need it.

--
Remove del for email

Leslie Milburn

unread,
Dec 19, 2009, 3:58:38 AM12/19/09
to

"Robby" wrote:

Hi Robby,

I am not a fan of global variables at all. To use them is a last resort as
it implies a code design problem. In all my 25+ years of C programming I
have hard ever had to resort to using a global variable. I suggest you look
at the code once more and decide if the variable could be passed as a
parameter as needed.

>
> Objective:
> The data in the MQ array has to be accessible and available in many
> functions of several .c files, and therefore should appear to have global
> scope.

I disagree, pass the variable as a parameter to the functions that require
access to the variable. Yes *all* of them.


> Resolution:
> As shown in code above, I declared an array as "extern" and then defined
> it
> in one .c file and where ever other .c files require access to MQ[], I
> have
> to include the KERNEL.h file. Is this an okay practice to do with all
> other
> global variables, arrays and arrays of structures?
>

I have seen some programmers follow this approach. IMO over time the code
may become harder to read and you need to consider if any programmers other
than yourself will be maintaining the code. I always assume (even for my
private projects) that I will not be the only programmer reading the code.

My preferred approach is to declare the variable at the top of the .c module
in which it is first created and usually (but not always) populated. Then
for each .c module that requires access to the variable I place "extern
variable name" at the top of that module with a comment indicating why I am
using it. To make the code more readable I use the naming convention of
modulename_variablename to help identify where the declaration is located.
So in your case it would be api_MQ.

Of concern is that your choice of module name and variable names are not
really that meaningful. api.c and kernel.c are not useful names if you think
about it. Which API is api.c referring to. Also MQ also has little meaning.
Before you get to far down the road you might like to revisit your naming
conventions. My main software project comprises of approximately 400 .c
modules and it is easy to forget the finer details when you revisit code 12
to 18 months later. So trust me when I say you will be thankful you used
meaningful names.

hth
leslie.

Leslie Milburn

unread,
Dec 19, 2009, 4:03:55 AM12/19/09
to

"Barry Schwarz" wrote

>
> While this is obviously the right (tm) way to define a global variable
> exactly once and declare it extern everywhere it is needed, it begs
> the question of whether global variables are the right choice. Since
> they have a tendency to confound debugging, there is a school of
> thought that strongly recommends passing the array as an argument to
> those functions that need it.

Exactly.


Tim Roberts

unread,
Dec 20, 2009, 9:03:53 PM12/20/09
to
"Leslie Milburn" <CD...@NOSPAM.bigpond.com> wrote:
>
>I am not a fan of global variables at all. To use them is a last resort as
>it implies a code design problem. In all my 25+ years of C programming I
>have hard ever had to resort to using a global variable. I suggest you look
>at the code once more and decide if the variable could be passed as a
>parameter as needed.

Although I agree that his current implementation has an almost unlimited
number of problems, the big issue he's facing is that he's writing for an
embedded processor. On many embedded processors, such as the PIC series
that he's targeting, the stack is your enemy. It can be very expensive to
use parameters and stack local variables, so you end up using globals more
than you ordinarily would.
--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Barry Schwarz

unread,
Dec 21, 2009, 12:03:02 AM12/21/09
to
On Sun, 20 Dec 2009 18:03:53 -0800, Tim Roberts <ti...@probo.com>
wrote:

Then he would be better off making it static in main and still passing
it as an argument.

But if stack space is the problem, why is he using long instead of
short or int.

Leslie Milburn

unread,
Dec 21, 2009, 3:09:08 AM12/21/09
to

"Tim Roberts" <ti...@probo.com> wrote:

> Although I agree that his current implementation has an almost unlimited
> number of problems, the big issue he's facing is that he's writing for an
> embedded processor. On many embedded processors, such as the PIC series
> that he's targeting, the stack is your enemy. It can be very expensive to
> use parameters and stack local variables, so you end up using globals more
> than you ordinarily would.

Then the static keyword is your friend as it is allocated the once and it
can then be passed as a parameter as required. IMO this is much cleaner !!
Leslie.


Robby

unread,
Dec 21, 2009, 1:14:04 PM12/21/09
to
"Barry Schwarz" wrote:

> But if stack space is the problem, why is he using long instead of
> short or int.

Because I am porting from an 8bit MCU to a 32 bit MCU and in the 8 bit MCU a
long is only 16 bits wide. In summary a long in an 8 bit MCU = a short in a
32 bit MCU !

Eventually I will change this:

long MQ[10]; >>>>>>>>> to this: int MQ[10];

But before I start changing var types and create a grave for myself here, I
have to take baby steps and do one thing at a time. So first I bring over the
program exactly the way it is and see if it even compiles... because remember
I am porting a program from a non C compliant compiler to a C compliant
compiler. I have a feeling I will see many things like this global variable
issue come up.

Rob

Robby

unread,
Dec 21, 2009, 1:39:01 PM12/21/09
to
"Leslie Milburn" wrote:

> My preferred approach is to declare the variable at the top of the .c module
> in which it is first created and usually (but not always) populated. Then
> for each .c module that requires access to the variable I place "extern
> variable name" at the top of that module with a comment indicating why I am
> using it. To make the code more readable I use the naming convention of
> modulename_variablename to help identify where the declaration is located.
> So in your case it would be api_MQ.

So leslie, please confirm to me that what you are suggesting is this:
=====================KERNAL.h
//...

=====================KERNAL.c
#include "KERNAL.h"


long MQ[10] = {1,2,3,4,5,6,7,8,9,0}; // <at top of a particular .c file!

=====================API.c
#include "API.h" // API.h not showm !!!
extern long MQ[10]; // Global Message queue variable

void API_InsertMessage(enum enumKM m)
{ MQ[0] = m; }
===========================

I have not tried the above code, but from the paragraph you wrote it seems
to be what you are recommending! and its okay with me.

However, my original sample would work aswell... to be noted here, MQ is my
only global variable I need in my whole project. The rest of the application
declares structures and preprocessor commands in header files.

Thankyou all for your replies. Sorry for the delay!

regards
Robert

Leslie Milburn

unread,
Dec 21, 2009, 8:33:59 PM12/21/09
to

"Robby" <Ro...@discussions.microsoft.com> wrote in message
news:D7E4F275-613E-46DF...@microsoft.com...

> "Leslie Milburn" wrote:
>
> So leslie, please confirm to me that what you are suggesting is this:
> =====================KERNAL.h
> //...
>
> =====================KERNAL.c
> #include "KERNAL.h"
> long MQ[10] = {1,2,3,4,5,6,7,8,9,0}; // <at top of a particular .c file!

Yes.

> =====================API.c
> #include "API.h" // API.h not showm !!!
> extern long MQ[10]; // Global Message queue variable
>

Yes

>
> However, my original sample would work aswell... to be noted here, MQ is
> my
> only global variable I need in my whole project. The rest of the
> application
> declares structures and preprocessor commands in header files.

Yes, what you wrote will work but you are placing what I consider to be code
in header files, not something I like.
Leslie.


Ron Francis

unread,
Dec 21, 2009, 10:09:15 PM12/21/09
to
"Robby" <Ro...@discussions.microsoft.com> wrote in message
news:D7E4F275-613E-46DF...@microsoft.com...

I tend to do the same as Leslie.
Probably not applicable in your case if you only have one global variable, but what I have done is
create a header file with a list of externals that gets included in any files that need them
=====================external.h
extern long MQ[10];
//add any externals that you need

In this way, if you need to create any more variables that you need to access from other files, you
can just add it to the one header rather than to each file.
It may be less obvious, but it can save some legwork if there are lots of files and you need to
change something.

Ron.

Robby

unread,
Dec 22, 2009, 11:18:09 AM12/22/09
to
Hello Leslie,

"Leslie Milburn" wrote:

In all due respect Leslie, I don't see where I am placing code in header
files.

=====================KERNAL.h
//...
=====================KERNAL.c
#include "KERNAL.h"
long MQ[10] = {1,2,3,4,5,6,7,8,9,0};

=====================API.c
#include "API.h" // API.h not showm !!!
extern long MQ[10];

=========================

???? confused ???

Rob

Robby

unread,
Dec 22, 2009, 12:02:01 PM12/22/09
to
"Ron Francis" wrote:
> I tend to do the same as Leslie.
> Probably not applicable in your case if you only have one global variable, but what I have done is
> create a header file with a list of externals that gets included in any files that need them
> =====================external.h
> extern long MQ[10];
> //add any externals that you need
>
> In this way, if you need to create any more variables that you need to access from other files, you
> can just add it to the one header rather than to each file.
> It may be less obvious, but it can save some legwork if there are lots of files and you need to
> change something.

So in this case, I would still have to populate the MQ array in another .c
file? right?

Regards
Rob

Robby

unread,
Dec 22, 2009, 12:44:02 PM12/22/09
to
Hello Ron, one more thing,

I have tried your suggestion but it compiles with an error. Here is the code:


===============KERNEL.h
enum enumKM{KM_QUIT = 0, KM_CREATE = 1, KM_RECUR = 2};
extern long MQ[10];

===============KERNEL.c
#include <stdio.h>
#include "KERNEL.h"
#include "API.h"

int main()
{
API_InsertMessage(KM_QUIT);
return 0;
}
===============API.h
void API_InsertMessage(enum enumKM m);

===============API.c
#include "API.h"
#include "KERNEL.h"

void API_InsertMessage(enum enumKM m)
{
long h=1;
MQ[1]= h;
}
==========================

The following error is reported at compile time:

1>API.obj : error LNK2001: unresolved external symbol _MQ

And I did include KERNEL.h in API.c as you indicated ?????

>Probably not applicable in your case if you only have one global variable, but what >I have done is create a header file with a list of externals that gets included in any > files that need them

--
Best regards
Roberto


"Ron Francis" wrote:

> .
>

Robby

unread,
Dec 22, 2009, 2:59:03 PM12/22/09
to
Ron,

I don't think I would create a header file just dedicated to global externs.
Becuase, then why not dedicate a header file for more than just extersn...
why not just for externs and #defines and where do you draw the line as to
what else we can put in there. So I would be mre comfortable with a KERNEL.h
and put the exters, #defines and some struct declarations and include
KERNEL.h in every .c file.

So getting back to your suggestion, I guess that you meant it to be coded
this way:

===============KERNEL.h
enum enumKM{KM_QUIT = 0, KM_CREATE = 1, KM_RECUR = 2};
extern long MQ[10];

===============KERNEL.c
#include <stdio.h>
#include "KERNEL.h"
#include "API.h"

long MQ[2] = {1,2];

int main()
{
API_InsertMessage(KM_QUIT);
return 0;
}
===============API.h
void API_InsertMessage(enum enumKM m);

===============API.c
#include "API.h"
#include "KERNEL.h"

void API_InsertMessage(enum enumKM m)
{
long h=1;
MQ[1]= h;
}
==========================

Now the above compiles without errors or warnings.

Thanks all for your replies. Very appreciated

Leslie Milburn

unread,
Dec 22, 2009, 7:37:13 PM12/22/09
to

"Robby" <Ro...@discussions.microsoft.com> wrote in message
news:1955771B-260E-4B26...@microsoft.com...

>
> In all due respect Leslie, I don't see where I am placing code in header
> files.

I consider this to be code:

long MQ[10] = {1,2,3,4,5,6,7,8,9,0};

So is THIS

extern long MQ;

IMO they should not be placed into a header file even for a shortcut. Your
original approach to which I was referring to does have these declarations
in headers files hence you have code in header files. So yes your original
approach does work but I do not like it.

Remember just because it can be done doesn't mean it should be done. Just
take a look at the windows header files to see Microsoft created spaghetti.
Leslie.


Igor Tandetnik

unread,
Dec 22, 2009, 7:47:10 PM12/22/09
to
Leslie Milburn <CD...@NOSPAM.bigpond.com> wrote:
> "Robby" <Ro...@discussions.microsoft.com> wrote in message
> news:1955771B-260E-4B26...@microsoft.com...
>>
>> In all due respect Leslie, I don't see where I am placing code in
>> header files.
>
> I consider this to be code:
>
> long MQ[10] = {1,2,3,4,5,6,7,8,9,0};
>
> So is THIS
>
> extern long MQ;
>
> IMO they should not be placed into a header file even for a shortcut.

How do you propose to declare a global variable then, so that it can be shared between source files?

> Your original approach to which I was referring to does have these
> declarations in headers files hence you have code in header files.

If you can't have declarations in headers, what _can_ you have in headers?
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925

Leslie Milburn

unread,
Dec 22, 2009, 8:06:54 PM12/22/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:%23t%23D3l2g...@TK2MSFTNGP02.phx.gbl...

> How do you propose to declare a global variable then, so that it can be
> shared between source files?

Firstly I never propose to use a global variable :-)
Secondly read my previous posts for the answer to how you should declare a
global variable and how it is used from other modules.

> If you can't have declarations in headers, what _can_ you have in headers?

By declarations I meant variables. Looking at my header files I only have
the following in my header files #defines, typedefs, function declarations
and not much else really. That was the original intention of header files
after all. Code should be place into .c modules always.
Leslie.


Igor Tandetnik

unread,
Dec 22, 2009, 8:26:49 PM12/22/09
to
Leslie Milburn <CD...@NOSPAM.bigpond.com> wrote:
> "Igor Tandetnik" <itand...@mvps.org> wrote in message
> news:%23t%23D3l2g...@TK2MSFTNGP02.phx.gbl...
>> How do you propose to declare a global variable then, so that it can
>> be shared between source files?
>
> Firstly I never propose to use a global variable :-)
> Secondly read my previous posts for the answer to how you should
> declare a global variable and how it is used from other modules.

Ah. Basically, you say - instead of putting a line of code into a header and then including that header where needed, let's duplicate this line in every source file. Then, if you ever need to change the declaration, you'll have to hunt down all copies.

In other words, let's create precisely the problem that include files are supposed to solve. I don't quite see how this is an improvement.

>> If you can't have declarations in headers, what _can_ you have in
>> headers?
>
> By declarations I meant variables. Looking at my header files I only
> have the following in my header files #defines, typedefs, function
> declarations and not much else really.

I'm not sure I see the difference between a function declaration and a variable declaration that would make the former acceptable in a header and the latter unacceptable. I understand that one shouldn't place variable definitions into headers, anymore than one would function definitions. But declarations?

> That was the original
> intention of header files after all. Code should be place into .c
> modules always.

extern int x; // [1]
extern int f(); // [2]
typedef int I; // [3]

What makes [1] "code" but [2] and [3] "not code"?

Leslie Milburn

unread,
Dec 22, 2009, 8:47:52 PM12/22/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote:

> Ah. Basically, you say - instead of putting a line of code into a header
> and then including that header where needed, let's duplicate this line in
> every source file.
> Then, if you ever need to change the declaration, you'll have to hunt down
> all copies.

Yes. It works for me because the variable name itself tells me in which
module it was declared so there is no hunting for the decaration as I can go
straight to the module where it lives, no problems.


> In other words, let's create precisely the problem that include files are
> supposed to solve. I don't quite see how this is an improvement.

No what I am saying is that I do not want my header files to look like the
Windows Platform SDK header file. My header files are clean and readable and
have worked well for years.


> I'm not sure I see the difference between a function declaration and a
> variable declaration that would make the former acceptable in a header and
> the latter unacceptable. I understand that one shouldn't place variable
> definitions into headers, anymore than one would function definitions. But
> declarations?

My mistake I meant function definitions.

> extern int x; // [1]
> extern int f(); // [2]
> typedef int I; // [3]

> What makes [1] "code" but [2] and [3] "not code"?

3 is a type definition and therefore not code. There is no way to use this
in other .c modules without duplication so it goes in a header file. 1 and 2
can be placed in a .c module and therefore should be. Thats the difference.

Just to make a guess here , but I bet you place code for member functions of
C++ classes into header files with the along with the class definition. Yes
?
If so then we will not agree on this subject.
Leslie.


Igor Tandetnik

unread,
Dec 22, 2009, 9:17:08 PM12/22/09
to
Leslie Milburn <CD...@NOSPAM.bigpond.com> wrote:
> "Igor Tandetnik" <itand...@mvps.org> wrote:
>
>> Ah. Basically, you say - instead of putting a line of code into a
>> header and then including that header where needed, let's duplicate
>> this line in every source file.
>> Then, if you ever need to change the declaration, you'll have to
>> hunt down all copies.
>
> Yes. It works for me because the variable name itself tells me in
> which module it was declared so there is no hunting for the
> decaration as I can go straight to the module where it lives, no
> problems.

You mean, the module where it is _defined_, not declared. According to your description, it's declared anew in every source file that refers to it.

>> In other words, let's create precisely the problem that include
>> files are supposed to solve. I don't quite see how this is an
>> improvement.
>
> No what I am saying is that I do not want my header files to look
> like the Windows Platform SDK header file. My header files are clean
> and readable and have worked well for years.

Well, if you keep your header files empty, they will be even cleaner and more readable. I don't quite see how taking a line from one file and duplicating it in several other files improves overall readability, while it clearly adds to maintenance burden.

As to Platform SDK, I can't seem to recall off the top of my head any global variables declared there. If they are unreadable, it's not because of variable declarations.

>> I'm not sure I see the difference between a function declaration and
>> a variable declaration that would make the former acceptable in a
>> header and the latter unacceptable. I understand that one shouldn't
>> place variable definitions into headers, anymore than one would
>> function definitions. But declarations?
>
> My mistake I meant function definitions.

Wait a minute. Are you saying you have function definitions in your headers? How do you get that to build?

>> extern int x; // [1]
>> extern int f(); // [2]
>> typedef int I; // [3]
>
>> What makes [1] "code" but [2] and [3] "not code"?
>
> 3 is a type definition and therefore not code. There is no way to use
> this in other .c modules without duplication so it goes in a header
> file. 1 and 2 can be placed in a .c module and therefore should be.
> Thats the difference.

I don't follow. You can place [3] in as many .c source files as you want, just as you can [1] and [2]. Or, you can place all three in a header and include that into several .c files. What again is the difference?

> Just to make a guess here , but I bet you place code for member
> functions of C++ classes into header files with the along with the
> class definition. Yes ?

No. Member function definitions go into .cpp files. Declarations, of course, go into header files.

I'm beginning to wonder - do you understand the difference between a declaration and a definition?

// This is function declaration
void f();

// This is function definition
void f() {
}

// This is variable declaration
extern int x;

// This is variable definition
int x;

A variable or function (with external linkage) needs to be declared in every translation unit before it is used (possibly by #including the header file containing the declaration), but it must be defined exactly once in the whole program.

Pavel A.

unread,
Dec 22, 2009, 10:50:28 PM12/22/09
to

All this just confirms the old Russian proverb - that one user can
ask a question that 100 admins won't answer.
--pa


"Igor Tandetnik" <itand...@mvps.org> wrote in message

news:urOXIY3g...@TK2MSFTNGP02.phx.gbl...

Tim Roberts

unread,
Dec 22, 2009, 11:04:35 PM12/22/09
to

I don't think you appreciate the problem. You've been working for too long
in systems with infinite memory and infinitely fast processors.

Parameters are part of the problem, as I said in my post. Sure, the code
is architecturally more "pure" by using parameters, but when your stack is
only 16 bytes long and it costs a dozen cycles to change stacks, you have
to make different choices.

David Wilkinson

unread,
Dec 23, 2009, 6:29:42 AM12/23/09
to

MQ[10] is declared but not defined.

If it is declared in KERNEL.h, it should be defined in KERNEL.c.

--
David Wilkinson
Visual C++ MVP

David Wilkinson

unread,
Dec 23, 2009, 6:32:05 AM12/23/09
to

It does?

You have

extern long MQ[10]; // declaration

long MQ[2] = {1,2]; // definition

Ron Francis

unread,
Dec 23, 2009, 7:54:02 AM12/23/09
to
"Robby" <Ro...@discussions.microsoft.com> wrote in message
news:C81EE069-E512-4220...@microsoft.com...

Robby,

Please excuse me being obvious, but I'm not sure how much you understand.
Yes, you still have to define MQ and it would make sense to do that in your KERNAL.c
When you use 'extern', you are just telling the compiler that the variable is defined elsewhere and
because the compiler couldn't find a definition anywhere, you got the error..

If you want to use MQ in another file, you have to tell it that it is defined somewhere else, so
normally you would normally put
extern long MQ [10];
near the beginning of the file.
Anyone reading the file can easily see that MQ is defined somewhere else.
If you 'hide' the declaration in KERNAL.h then someone would have to search for it.

You can think of a header file as just being an addition to a *.c file that it is embedded in.
That is, you can read it as all one file.

That is why David said ...
"You have
extern long MQ[10]; // declaration
long MQ[2] = {1,2]; // definition"
Because you have included KERNAL.h within KERNAL.c, it becomes one file and so you have made a
declaration and definition within the same file.
I'm surprised that it compiles but I don't know much about how compilers work.

Getting back to hiding the declaration, in my case, I put all my externs in their own header file
for readability.
Someone looking through a file wouldn't see an extern keyword, but I thought the next best thing
would be to see extern.h and hopefully assume that it would contain declarations.
If I had lots of #defines I would probably have a separate defines.h file, but I don't know that
this is common practice.
I think it is (or was) common to prefix a lowercase "g" to a variable to denote that it is global.
Something like g_MQ.

I know very little compared to many here, so I hope I haven't led you astray.
I'm sure I'll be corrected if I said something wrong.

Ron.

David Wilkinson

unread,
Dec 23, 2009, 8:51:03 AM12/23/09
to
David Wilkinson wrote:
> It does?
>
> You have
>
> extern long MQ[10]; // declaration
>
> long MQ[2] = {1,2]; // definition

Robby:

Actually, I now see that in the above (which I copied from your post), there is
an obvious typo in the definition, so the code most certainly will not compile.

I realize that your real code is too long to post, but there is a real danger in
just typing code into a post, because you will inevitably introduce errors that
are unrelated to the question you are asking.

The point under discussion could have been illustrated by the single file
complete program

extern long MQ[10]; // declaration

long MQ[2] = {1,2]; // definition

int main()
{
long n = MQ[0];
return 0;
}

If you had pasted this code into a test console project (as I did), you would
immediately have found two compiler errors.

After correcting the errors, you would find that if you commented out the
definition above (leaving only the declaration) then you would get a linker error.

Even if it does not help you to figure out the problem yourself, putting all the
code in a single file greatly increases the chance that a reader will paste your
code into a test project and figure it out for you. I always have such a test
project available for precisely this purpose.

Barry Schwarz

unread,
Dec 23, 2009, 9:41:53 AM12/23/09
to
On Wed, 23 Dec 2009 23:24:02 +1030, "Ron Francis"
<ronfr...@adam.com.au> wrote:

snip

>Please excuse me being obvious, but I'm not sure how much you understand.
>Yes, you still have to define MQ and it would make sense to do that in your KERNAL.c
>When you use 'extern', you are just telling the compiler that the variable is defined elsewhere and
>because the compiler couldn't find a definition anywhere, you got the error..
>
>If you want to use MQ in another file, you have to tell it that it is defined somewhere else, so
>normally you would normally put
>extern long MQ [10];
>near the beginning of the file.
>Anyone reading the file can easily see that MQ is defined somewhere else.
>If you 'hide' the declaration in KERNAL.h then someone would have to search for it.
>
>You can think of a header file as just being an addition to a *.c file that it is embedded in.
>That is, you can read it as all one file.
>
>That is why David said ...
>"You have
>extern long MQ[10]; // declaration
>long MQ[2] = {1,2]; // definition"
>Because you have included KERNAL.h within KERNAL.c, it becomes one file and so you have made a
>declaration and definition within the same file.
>I'm surprised that it compiles but I don't know much about how compilers work.

The issue being raised was not that the declaration and definition
were in the same translation unit but that they were inconsistent
within that unit, along with the obvious typographical error.

Igor Tandetnik

unread,
Dec 23, 2009, 11:24:32 AM12/23/09
to
Pavel A. <pav...@12fastmail34.fm> wrote:
> All this just confirms the old Russian proverb - that one user can
> ask a question that 100 admins won't answer.

First recorded in Italy in 17th century, apparently:

http://www.encyclopedia.com/doc/1O90-FLSskqstnsthtwsmncnntnswr.html

Robby

unread,
Dec 23, 2009, 1:01:01 PM12/23/09
to
"David Wilkinson" wrote:

"David Wilkinson" wrote:

Yes David, I understand your point, but the original question concerned on
how to declare global variables with multiple files, so I figured to post
something as realistic as possible to the core of my question. Don't forget I
still am a little shaky with the right way of using the #includes since all
this time I was used to including headers just once in a particular .c file.

About the typo's ... I am rushing all the time to try to keep up with all
the propositions. And I really don't know how I do these typo's... I always
try them first in VC++ and then I paste them as they are. My fault I know!

Sorry for the typo, I now have tested it, and this is what I meant:

> ===============KERNEL.h
enum enumKM{KM_QUIT = 0, KM_CREATE = 1, KM_RECUR = 2};

extern long MQ[2];

===============KERNEL.c
#include <stdio.h>
#include "KERNEL.h"
#include "API.h"

long MQ[2] = {1,2};

int main()
{ API_InsertMessage(KM_QUIT); return 0; }

===============API.h
void API_InsertMessage(enum enumKM m);

===============API.c
#include "API.h"
#include "KERNEL.h"

void API_InsertMessage(enum enumKM m)
{MQ[1]= 1;}
==========================

I just don't see how we are not supposed to declare extern's in our header
file. I know theres a dispute going on here, I didn't read it til the to see
how it ends up, but how can we say that

extern int x;

is code ?????

I include this in many .c files and I don't get any variable duplication
errors ???

Thanks for your reply!

Rob

Robby

unread,
Dec 23, 2009, 1:56:05 PM12/23/09
to
"Ron Francis" wrote:

> Please excuse me being obvious, but I'm not sure how much you understand.

Not much... obviously!

> Yes, you still have to define MQ and it would make sense to do that in your KERNAL.c
> When you use 'extern', you are just telling the compiler that the variable is defined elsewhere and
> because the compiler couldn't find a definition anywhere, you got the error..
> If you want to use MQ in another file, you have to tell it that it is defined somewhere else, so normally you would normally put
> extern long MQ [10];
> near the beginning of the file. Anyone reading the file can easily see that MQ is defined somewhere else.

Understood.

> If you 'hide' the declaration in KERNAL.h then someone would have to search for > it. You can think of a header file as just being an addition to a *.c file that it is
> embedded in.
> That is, you can read it as all one file.
>
> That is why David said ...
> "You have
> extern long MQ[10]; // declaration
> long MQ[2] = {1,2]; // definition"
> Because you have included KERNAL.h within KERNAL.c, it becomes one file and so you have made a
> declaration and definition within the same file.
> I'm surprised that it compiles but I don't know much about how compilers work.

Yes, but if you try to do this:

==============Kernel.c
#include <stdio.h>
#include "API.h"

extern long MQ[2];


long MQ[2] = {1,2};

int main()
{
return 0;
}
=================

It should compile without errors! My point is that we should be able to
declare a variable and then define it down stream of our program... so what
is the difference if we declare it in a header and include that header in a
.c file and define that variable then.

In other words, what is the harm if we do this:
===============KERNEL.h
extern long MQ[2]; // *** DECLARED ***

===============KERNEL.c
#include <stdio.h>
#include "KERNEL.h"
#include "API.h"

long MQ[2] = {1,2}; // *** DEFINED ***

int main()
{return 0; }
==================

> Getting back to hiding the declaration, in my case, I put all my externs in their >own header file for readability. Someone looking through a file wouldn't see an >extern keyword, but I thought the next best thing would be to see extern.h and >hopefully assume that it would contain declarations.

I like this proposition more and more to declare all the externs in a
seperate header file and define each extern in exactlty one .c file and
include the extern header file in every other .c file as required. This makes
the best sence since when a user looks at a .c file and sees the inclusion of
the extern.h file, he knows that this .c file uses global variables. But now,
we have Leslie that discourages the use of extern in a header file... if I am
mistaken... or I think this was resolved as allowable to do so. I don't know
anymore... too many ways of doing a simple task.

Your proposition seems to compile in VC++ and MPLAB without errors or
warnings.
So I like your proposition and I am sticking to it. :-)

> If I had lots of #defines I would probably have a separate defines.h file, but I don't know that this is common practice.

Perhaps this too could be good... but I can't say for sure!

> I know very little compared to many here, so I hope I haven't led you astray.
> I'm sure I'll be corrected if I said something wrong.

I know the least compared to all of them. However, I do appreciate their
help! :-)

Thankyou Ron for your help.
Thanks to all your feedback and happy holidays to all!

Regards
Rob

sasha

unread,
Dec 23, 2009, 3:31:43 PM12/23/09
to

Tim Roberts wrote:

> Parameters are part of the problem, as I said in my post. Sure, the code
> is architecturally more "pure" by using parameters, but when your stack is
> only 16 bytes long and it costs a dozen cycles to change stacks, you have
> to make different choices.


Then the parameters are passed by a pointer to a list of parameters
stored elsewhere (like IBM System 360 did).

It's up to a compiler to figure out how to do that :)

David Wilkinson

unread,
Dec 24, 2009, 8:00:21 AM12/24/09
to

Robby wrote:

> I just don't see how we are not supposed to declare extern's in our header
> file. I know theres a dispute going on here, I didn't read it til the to see
> how it ends up, but how can we say that
>
> extern int x;
>
> is code ?????
>
> I include this in many .c files and I don't get any variable duplication
> errors ???

I think the argument is about whether you should be using global variables at
all. If you are going to use them, IMHO absolutely the right way to do it is

1. declare each variable using extern in some .h file

2. define it just once in a single .c file

3. #include the .h file in every .c file that uses the variable

This way, if you want to change from (say)

long MQ[2];

to (say)

long MQ[10];

you only have to change your code in two places (the extern declaration in the
.h file, and the definition in the .c file).

sasha

unread,
Dec 24, 2009, 1:51:58 PM12/24/09
to
David Wilkinson wrote:

> I think the argument is about whether you should be using global variables at
> all. If you are going to use them, IMHO absolutely the right way to do it is
>
> 1. declare each variable using extern in some .h file
>
> 2. define it just once in a single .c file
>

One may go even further and use something like this:

#if !defined VAR_DEFINITION
extern
#endif

long MQ [2];

Have the VAR_DEFINITION defined in one .cpp file among all that include
the .h file.

This way there is only one place to change.

Ron Francis at

unread,
Dec 25, 2009, 11:36:49 PM12/25/09
to
"Barry Schwarz" <schw...@dqel.com> wrote in message
news:sva4j5pobsv6k18n3...@4ax.com...

Oh God, that was so obvious and I missed it!
Thanks Barry.

Ron.


Ron Francis at

unread,
Dec 26, 2009, 12:20:01 AM12/26/09
to
"Robby" <Ro...@discussions.microsoft.com> wrote in message
news:281073CD-90FC-4DC2...@microsoft.com...
> "Ron Francis" wrote:

<snip>

>> That is why David said ...
>> "You have
>> extern long MQ[10]; // declaration
>> long MQ[2] = {1,2]; // definition"

My mistake here.
You have declared an array of 10 elements and defined an array of 2
elements.

<snip>

Yes, that should compile and run without errors, and the only reason that I
can see for not doing it is that the declaration may not be easy to find, as
discussed below.

>> Getting back to hiding the declaration, in my case, I put all my externs
>> in their
>>own header file for readability. Someone looking through a file wouldn't
>>see an
>>extern keyword, but I thought the next best thing would be to see extern.h
>>and
>>hopefully assume that it would contain declarations.
>
> I like this proposition more and more to declare all the externs in a
> seperate header file and define each extern in exactlty one .c file and
> include the extern header file in every other .c file as required. This
> makes
> the best sence since when a user looks at a .c file and sees the inclusion
> of
> the extern.h file, he knows that this .c file uses global variables. But
> now,
> we have Leslie that discourages the use of extern in a header file... if I
> am
> mistaken... or I think this was resolved as allowable to do so. I don't
> know
> anymore... too many ways of doing a simple task.

Leslie would have to answer this, but I suspect that readability has a lot
to do with it.
I imagine that anyone seeing an unknown variable would look first at the top
of the file for its definition or declaration.
If you have many *.h files then the reader has no idea where to look.
Yes, it can be searched for, but then it has to be remembered or at least a
comment added.

By far, the most readable would be
extern long MQ[2];
near the top of the file.

One reason that I have used extern.h files is for easy editing.
What if I wanted to change it to
extern long MQ[3];
If I had 50 extern declarations, I would have to change them all, plus the
definition.
But if it was embedded in an extern.h file then I would only have edit it in
two places.
Keep in mind that any loops etc would have to change too.
You are right that there are lots of ways to do the same thing, and although
confusing, it is also a blessing because it is less limiting.
Probably a more sensible approach is something like:
=====kernal.h
#define MQ_SIZE 2
long MQ[MQ_SIZE] = {1,2};

=====extern.h
extern long MQ[MQ_SIZE];
//extern declarations could also be at the top of each
//and they wouldn't have to be edited

Any loops etc would then be
for(int i=0; i<MQ_SIZE; i++){
//whatever
}
Then only the definition MQ_SIZE would have to be changed.

But as I said earlier, I really don't know if this is good coding practice
or not.

<snip>

> Regards
> Rob

Cheers,
Ron Francis
www.RonaldFrancis.com

0 new messages