Discussion:
extern for global variable: C Question
(too old to reply)
Robby
2009-12-18 18:07:01 UTC
Permalink
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
2009-12-18 18:34:12 UTC
Permalink
Post by Robby
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
2009-12-18 19:34:01 UTC
Permalink
Thank you Dave!
--
Best regards
Roberto
Post by Robby
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
.
Barry Schwarz
2009-12-19 08:58:11 UTC
Permalink
On Fri, 18 Dec 2009 18:34:12 +0000, David Lowndes
Post by Robby
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.
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
2009-12-19 09:03:55 UTC
Permalink
Post by Barry Schwarz
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.
mzdude
2009-12-18 21:54:21 UTC
Permalink
On Dec 18, 1:07 pm, Robby <***@discussions.microsoft.com> wrote:
<snip>
Post by Robby
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.
Leslie Milburn
2009-12-19 08:58:38 UTC
Permalink
"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.
Post by Robby
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.
Post by Robby
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.
Tim Roberts
2009-12-21 02:03:53 UTC
Permalink
Post by Leslie Milburn
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, ***@probo.com
Providenza & Boekelheide, Inc.
Barry Schwarz
2009-12-21 05:03:02 UTC
Permalink
Post by Tim Roberts
Post by Leslie Milburn
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.
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.
--
Remove del for email
Robby
2009-12-21 18:14:04 UTC
Permalink
Post by Barry Schwarz
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
Leslie Milburn
2009-12-21 08:09:08 UTC
Permalink
Post by Tim Roberts
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.
Tim Roberts
2009-12-23 04:04:35 UTC
Permalink
Post by Leslie Milburn
Post by Tim Roberts
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 !!
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.
--
Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc.
sasha
2009-12-23 20:31:43 UTC
Permalink
Post by Tim Roberts
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 :)
Robby
2009-12-21 18:39:01 UTC
Permalink
Post by Leslie Milburn
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
2009-12-22 01:33:59 UTC
Permalink
Post by Robby
=====================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.
Post by Robby
=====================API.c
#include "API.h" // API.h not showm !!!
extern long MQ[10]; // Global Message queue variable
Yes
Post by Robby
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.
Robby
2009-12-22 16:18:09 UTC
Permalink
Hello Leslie,
Post by Leslie Milburn
Post by Robby
=====================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.
Post by Robby
=====================API.c
#include "API.h" // API.h not showm !!!
extern long MQ[10]; // Global Message queue variable
Yes
Post by Robby
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.
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
Leslie Milburn
2009-12-23 00:37:13 UTC
Permalink
Post by Robby
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
2009-12-23 00:47:10 UTC
Permalink
Post by Robby
Post by Robby
In all due respect Leslie, I don't see where I am placing code in
header files.
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?
Post by Robby
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
2009-12-23 01:06:54 UTC
Permalink
Post by Igor Tandetnik
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.
Post by Igor Tandetnik
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
2009-12-23 01:26:49 UTC
Permalink
Post by Leslie Milburn
Post by Igor Tandetnik
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.
Post by Leslie Milburn
Post by Igor Tandetnik
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?
Post by Leslie Milburn
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"?
--
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
2009-12-23 01:47:52 UTC
Permalink
Post by Igor Tandetnik
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.
Post by Igor Tandetnik
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.
Post by Igor Tandetnik
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.
Post by Igor Tandetnik
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
2009-12-23 02:17:08 UTC
Permalink
Post by Leslie Milburn
Post by Igor Tandetnik
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.
Post by Leslie Milburn
Post by Igor Tandetnik
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.
Post by Leslie Milburn
Post by Igor Tandetnik
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?
Post by Leslie Milburn
Post by Igor Tandetnik
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?
Post by Leslie Milburn
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.
--
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
Pavel A.
2009-12-23 03:50:28 UTC
Permalink
All this just confirms the old Russian proverb - that one user can
ask a question that 100 admins won't answer.
--pa
Post by Igor Tandetnik
Post by Leslie Milburn
Post by Igor Tandetnik
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.
Post by Leslie Milburn
Post by Igor Tandetnik
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.
Post by Leslie Milburn
Post by Igor Tandetnik
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?
Post by Leslie Milburn
Post by Igor Tandetnik
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?
Post by Leslie Milburn
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.
--
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
Igor Tandetnik
2009-12-23 16:24:32 UTC
Permalink
Post by Pavel A.
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
--
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
Ron Francis
2009-12-22 03:09:15 UTC
Permalink
Post by Robby
Post by Leslie Milburn
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.
=====================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
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
2009-12-22 17:02:01 UTC
Permalink
Post by Ron Francis
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
2009-12-22 17:44:02 UTC
Permalink
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
Post by Robby
Post by Leslie Milburn
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.
=====================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
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
2009-12-22 19:59:03 UTC
Permalink
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
David Wilkinson
2009-12-23 11:32:05 UTC
Permalink
Post by Robby
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
===============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.
It does?

You have

extern long MQ[10]; // declaration

long MQ[2] = {1,2]; // definition
--
David Wilkinson
Visual C++ MVP
David Wilkinson
2009-12-23 13:51:03 UTC
Permalink
Post by David Wilkinson
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.
--
David Wilkinson
Visual C++ MVP
Robby
2009-12-23 18:01:01 UTC
Permalink
Post by David Wilkinson
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;
}
Post by David Wilkinson
It does?
You have
extern long MQ[10]; // declaration
long MQ[2] = {1,2]; // definition
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;
}
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!
Post by David Wilkinson
===============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
David Wilkinson
2009-12-24 13:00:21 UTC
Permalink
Post by Robby
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).
--
David Wilkinson
Visual C++ MVP
sasha
2009-12-24 18:51:58 UTC
Permalink
Post by David Wilkinson
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
2009-12-23 12:54:02 UTC
Permalink
Post by Robby
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
===============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
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.
Barry Schwarz
2009-12-23 14:41:53 UTC
Permalink
On Wed, 23 Dec 2009 23:24:02 +1030, "Ron Francis"
<***@adam.com.au> wrote:

snip
Post by Ron Francis
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.
--
Remove del for email
unknown
2009-12-26 04:36:49 UTC
Permalink
Post by Barry Schwarz
On Wed, 23 Dec 2009 23:24:02 +1030, "Ron Francis"
Post by Ron Francis
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.
Oh God, that was so obvious and I missed it!
Thanks Barry.

Ron.

Robby
2009-12-23 18:56:05 UTC
Permalink
Post by Ron Francis
Please excuse me being obvious, but I'm not sure how much you understand.
Not much... obviously!
Post by Ron Francis
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.
Post by Ron Francis
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; }
==================
Post by Ron Francis
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. :-)
Post by Ron Francis
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!
Post by Ron Francis
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
unknown
2009-12-26 05:20:01 UTC
Permalink
<snip>
Post by Robby
Post by Ron Francis
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>
Post by Robby
==============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.
===============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; }
==================
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.
Post by Robby
Post by Ron Francis
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>
Post by Robby
Regards
Rob
Cheers,
Ron Francis
www.RonaldFrancis.com
David Wilkinson
2009-12-23 11:29:42 UTC
Permalink
Post by Robby
Hello Ron, one more thing,
===============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;
}
==========================
1>API.obj : error LNK2001: unresolved external symbol _MQ
And I did include KERNEL.h in API.c as you indicated ?????
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
Continue reading on narkive:
Loading...