Searching \ for '[EE] Global variables in projects with many C file' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/language/index.htm?key=c
Search entire site for: 'Global variables in projects with many C file'.

Exact match. Not showing close matches.
PICList Thread
'[EE] Global variables in projects with many C file'
2007\10\24@192731 by James Newton

face picon face
Ok, I figured this out on my own, after writing the post I tried the other
guys "static" keyword in my main.h file and that worked. I'm going to post
it anyway 'cause I like looking stupid... Err... No, I'm going to post it
because some day some other poor soul may have the same confusion. Had I
posted it, some kind soul would have replied "RTFM: static keyword, main.h"
Here is the original post.

The is undoubtedly a stupid question, but I've managed to confuse myself
enough that I need some help..

I'm working on probably the largest program I've ever done in C. There are 5
separate ".C" files and double that in ".H" files. Some of the C files are
being done by other people. I have main.c and .h, and another programmer is
doing flash.c and .h. My main, of course, includes flash.h as well as main.h
and his flash.c also includes both of those as well.

We need to access some "global" variables between us. E.g. a pair of count
down timer variables and a status flag byte. I have to decrement the timers
in the interrupt routine that I wrote and he sets those and waits for them
to empty at points in his code. We each set and reset flags in the status
byte and branch based on their settings.

Where and how do we define those variables?

The chip we are using is an MSP430F1611 and the compiler is IAR.

My understanding is that they should be declared in main.h so that the
declaration is seen in both places, but when I do that, it compiles ok, but
the linker complains that
" Error[e27]: Entry "Timer1" in module main (
D:\user\james\code\JAMES-WIP\msp430\logger\Debug\Obj\main.r43 ) redefined in
module flash ( D:\user\
james\code\JAMES-WIP\msp430\logger\Debug\Obj\flash.r43 ) "

This is the section of main.h:

volatile
BYTE Stat = STAT_NO;        // status

volatile
BYTE Timer1, Timer2;        // 10mS decrement timer

I think there must be come compiler setting that I'm missing that would make
it understand that those "two" variables are one and the same.

The guy writing FLASH.H seems to think they should only be defined in his
code, but says that using the "static" keyword will somehow make the values
available in main. When we do that, the compiler complains that "
Error[Pe020]: identifier "Timer1" is undefined
D:\user\james\code\JAMES-WIP\msp430\logger\main.c 77" and so on for the
other variables.


--
Some clueless guy

2007\10\24@195303 by Regulus Berdin

picon face
Hi James,

James Newton wrote:
>
> volatile
> BYTE Stat = STAT_NO;        // status
>
> volatile
> BYTE Timer1, Timer2;        // 10mS decrement timer

Put "extern" on the variables defined in .h files with no
initialization. And redefine them again in the .c file with the
initialization.

So the above should be in the .h:

 extern volatile
 BYTE Stat;        // status

 extern volatile
 BYTE Timer1, Timer2;        // 10mS decrement timer

And in the .c file:
 extern volatile
 BYTE Stat = STAT_NO;        // status

 extern volatile
 BYTE Timer1, Timer2;        // 10mS decrement timer

You should also put a compiler switch in the .h file to avoid double
declaration. Example:
--main.h--
#ifndef _MAIN_H_
#define _MAIN_H_
.
.
..code here..
.
#endif /*_MAIN_H_*/


regards,
Reggie

2007\10\24@195551 by Regulus Berdin

picon face
Regulus Berdin wrote:
> And in the .c file:
>  extern volatile
>  BYTE Stat = STAT_NO;    // status
>
>  extern volatile
>  BYTE Timer1, Timer2;    // 10mS decrement timer

Sorry the above should be only :
volatile
BYTE Stat = STAT_NO;    // status

volatile
BYTE Timer1, Timer2;    // 10mS decrement timer


Reggie

2007\10\24@195757 by Marcel Birthelmer

picon face
James,
the way we do this at work usually is by defining an INIT macro, like so:

#ifdef FOO_INIT
#define FOO_VAR
#else
#define FOO_VAR extern
#endif

and then all the variables in foo.h would be declared as

FOO_VAR int foo1; etc.

When including foo.h from foo.c, you would define FOO_INIT:

#define FOO_INIT
#include foo.h

That way, in foo.c the variables are declared as globals.

Everywhere else (main.c or whatnot), you would just do #include foo.h,
and there the variables are then marked as extern, referring to the
variable defined in foo.c .

This gets a little bit tricky when you want to initialize the
variables - you have to use a more complicated macro for that.

Hope this helps.
- Marcel

On 10/24/07, James Newton <spam_OUTjamesnewtonTakeThisOuTspammassmind.org> wrote:
{Quote hidden}

> -

2007\10\24@212407 by Mark Rages

face picon face
I define as extern in the header and as static in the C file.  Works
fine on the compilers I've used.

Regards,
Mark
markrages@gmail
--
Mark Rages, Engineer
Midwest Telecine LLC
.....markragesKILLspamspam@spam@midwesttelecine.com

2007\10\24@223841 by Matt Pobursky

flavicon
face
On Wed, 24 Oct 2007 16:28:16 -0700, James Newton wrote:
> I'm working on probably the largest program I've ever done in C. There
> are 5 separate ".C" files and double that in ".H" files. Some of the C
> files are being done by other people. I have main.c and .h, and another
> programmer is doing flash.c and .h. My main, of course, includes flash.h
> as well as main.h and his flash.c also includes both of those as well.
>
> We need to access some "global" variables between us. E.g. a pair of
> count down timer variables and a status flag byte. I have to decrement
> the timers in the interrupt routine that I wrote and he sets those and
> waits for them to empty at points in his code. We each set and reset
> flags in the status byte and branch based on their settings.
>
> Where and how do we define those variables?

I would write several timer access functions and keep the timer variable
private in the timer module. Global variables at the timer interrupt level
are a nasty bug waiting to happen. Sometimes they can't be avoided but
usually they can.

The rule would be only the timer ISR and the timer access functions can
change or access the timer variable(s). Add some functions like TimerSet(),
TimerExpired(), TimerRead(), etc. to the timer software module that are
public and allow other software modules access to timer status through one
method and place.

There is very low overhead for doing this and the functions are very simple
but they are also safe in that you know the timer variable(s) are only
accessed/changed in ONE place in the code. In general, globals are a bad
thing... ;-)

Matt Pobursky
Maximum Performance Systems



2007\10\24@225921 by Harold Hallikainen

face
flavicon
face
I define variables in the C file that does the most with the variable
(say, device.c). If the variable needs to be accessible from other files,
I put the variable in device.h using extern (ie, extern char something).

I mostly use static in defining local variables that are "remembered"
between function calls. To me, these are allocated like globals (not on
the stack) but have their scope limited so they can only be seen from
within the function. This contrasts with the default automatic variables
that are allocated and deallocated each time the function is invoked. I
understand the word static can also be used outside a function to limit
the scope of a variable to that particular source file. If a variable is
to be private to that source file, I just don't put it in the .h file. No
one else then knows about it.

Harold


{Quote hidden}

> -

2007\10\25@031104 by wouter van ooijen

face picon face
> Where and how do we define those variables?
> My understanding is that they should be declared in main.h so

The magic is in the separation of defining and declaring (iirc the
correct words):

in the .h: external int foo;

in one of the .c: int foo;

It is the same trick you use (probably without knowning) for functions:

.h:   foo();
.c:   foo(){...}

Wouter van Ooijen

-- -------------------------------------------
Van Ooijen Technische Informatica: http://www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: http://www.voti.nl/hvu




2007\10\25@051850 by Peter Bindels

picon face
On 25/10/2007, Marcel Birthelmer <marcelb.listsspamKILLspamgmail.com> wrote:
{Quote hidden}

#ifdef FOO_INIT
#define VAR_DECLARE(var, init) extern var
#else
#define VAR_DECLARE(var, init) var = init
#endif

[header]
VAR_DECLARE(int a, 42);
VAR_DECLARE(static int b, 12);
VAR_DECLARE(volatile int c, 44);
const int d = 45;
[/header]

The const is special since it is used as a compiler optimization that
requires it to be defined there. The rest means that there's an actual
variable that needs to be defined once in the program and declared
everytime you want to use it.

2007\10\25@053952 by William \Chops\ Westfield

face picon face

On Oct 24, 2007, at 4:28 PM, James Newton wrote:

> Where and how do we define those variables?

We have a rule that says .h files should never allocate actual space.
(well, hardly ever.)

So main.h should contain something like:
extern volatile BYTE Stat;

and then you can put the actual definition wherever it makes most sense.
Some compiler/linkers will overlap global external symbols with the same
name, but I wouldn't count on it.

Alternately, and better, you could add a bit to your source complexity
have have "globals.h" that provides the "extern ..." declarations, and
"globals.c" that contains nothing other than the global variable decls.

(the code I work with is about 60,000 files.)

"static" makes the variable local to your particular C file, a sort
of limited scoping.  It's NOT what you want for shared globals.

BillW

2007\10\25@054903 by William \Chops\ Westfield

face picon face

On Oct 24, 2007, at 7:38 PM, Matt Pobursky wrote:

> In general, globals are a bad thing.  [use accessor functions instead]

This is a good point too.  Although "low overhead" is in the mind of the
beholder.  I frequently cringe at the level of indirection it seems to
take for people to "safely" access what is essentially a global value.

BillW

2007\10\25@073430 by Byron Jeff

flavicon
face
On Wed, Oct 24, 2007 at 04:28:16PM -0700, James Newton wrote:
> Ok, I figured this out on my own, after writing the post I tried the other
> guys "static" keyword in my main.h file and that worked. I'm going to post
> it anyway 'cause I like looking stupid... Err... No, I'm going to post it
> because some day some other poor soul may have the same confusion. Had I
> posted it, some kind soul would have replied "RTFM: static keyword, main.h"
> Here is the original post.
>
> The is undoubtedly a stupid question, but I've managed to confuse myself
> enough that I need some help..
>
> I'm working on probably the largest program I've ever done in C. There are 5
> separate ".C" files and double that in ".H" files. Some of the C files are
> being done by other people. I have main.c and .h, and another programmer is
> doing flash.c and .h. My main, of course, includes flash.h as well as main.h
> and his flash.c also includes both of those as well.

That's SOP.

> We need to access some "global" variables between us. E.g. a pair of count
> down timer variables and a status flag byte. I have to decrement the timers
> in the interrupt routine that I wrote and he sets those and waits for them
> to empty at points in his code. We each set and reset flags in the status
> byte and branch based on their settings.
>
> Where and how do we define those variables?

You can only define them once. You then have to reference them multiple
times.

> The chip we are using is an MSP430F1611 and the compiler is IAR.

This is a standard C issue. Compiler and chip shouldn't matter.

>
> My understanding is that they should be declared in main.h so that the
> declaration is seen in both places, but when I do that, it compiles ok, but
> the linker complains that
> " Error[e27]: Entry "Timer1" in module main (
> D:\user\james\code\JAMES-WIP\msp430\logger\Debug\Obj\main.r43 ) redefined in
> module flash ( D:\user\
> james\code\JAMES-WIP\msp430\logger\Debug\Obj\flash.r43 ) "

Correct on the error. Each of the two objects thinks that it has its own
copy of the variables, and the linker whines about conflicting definitions.

>
> This is the section of main.h:
>
> volatile
> BYTE Stat = STAT_NO;        // status
>
> volatile
> BYTE Timer1, Timer2;        // 10mS decrement timer

Nope. Bad move. The rule is that one never actually defines a variable in a
header file for exactly the reason outlined above.

> I think there must be come compiler setting that I'm missing that would make
> it understand that those "two" variables are one and the same.

Yup. But it's not possible to declare that in a single place.

> The guy writing FLASH.H seems to think they should only be defined in his
> code,

That could work. But not in FLASH.H. FLASH.C.

> but says that using the "static" keyword will somehow make the values
> available in main.

Nope. Exactly the opposite. static states that the variable is local to the
file declaring it and that no outside code can get access.

> When we do that, the compiler complains that "
> Error[Pe020]: identifier "Timer1" is undefined
> D:\user\james\code\JAMES-WIP\msp430\logger\main.c 77" and so on for the
> other variables.

Bingo.

So here's that answer to the homework problem. When two separately compiled
code sections in C need to share a variable, one code section declares and
owns the variable, while the other simply references it using the header
file. This means that the variable in fact needs to be declared twice: once
in the code, and once in the header. So something like:

--------- FLASH.C -------------
#include "FLASH.H" // This is OK even though a second declaration exists
                  // The real definition overrides the extern.

volatile
BYTE Stat = STAT_NO;        // status
// This is the real and only definition of the variable
-------------------------------

--------- FLASH.H -------------
extern volatile
BYTE Stat = STAT_NO;        // status
// The extern indicates that the variable is defined elsewhere and that the
// linker should go find that definition in another compiled object.
-------------------------------

--------- MAIN.C --------------
#include "FLASH.H" // includes the extern declaration so MAIN.C can use the
                  // variable without having to declare it itself
-------------------------------

Note that no actual definition/declaration of the variable occurs in MAIN.C
except via the included declaration in FLASH.H. This way updates to the
declaration/definition of the variable only needs to occur in two places
instead of everywhere that the variable is used.

Hope this helps,

BAJ (Who used to teach C for several years)

2007\10\25@075502 by Byron Jeff

flavicon
face
On Wed, Oct 24, 2007 at 08:24:06PM -0500, Mark Rages wrote:
> I define as extern in the header and as static in the C file.  Works
> fine on the compilers I've used.

That got my Spidey sense tingling. So I had to try it. gcc 4.0.4 on a
Debian Linux box. Setup:

------------ a.c ---------------
#include <stdio.h>
#include "s.h"
static int junk;

main()
{
  junk = 1;
  printf("Junk = %d\n",junk);
  b();
  printf("Junk = %d\n",junk);
}
--------------------------------

------------ b.c ----------------
#include "s.h"

b()
{
  junk = 2;
}
---------------------------------

------------- s.h ---------------
extern int junk;
b();
---------------------------------

My gut says that the junk declared in a.c is isolated to a.c so b.c can't
see it. Since s.h only has an extern, then b.c has no real definition for
junk.

First off the compiler outsmarted me. I did the standard include along with
the declaration in a.c. The compiler didn't like that:

--------------------
cc    -c -o a.o a.c
In file included from a.c:2:
s.h:2: warning: data definition has no type or storage class
a.c:3: error: static declaration of 'junk' follows non-static declaration
s.h:1: error: previous declaration of 'junk' was here
--------------------

Good compiler. It knows that these are two different references. Just for
giggles I dropped the include in a.c and tried again. I got the expected:

--------------------
cc -o total a.o b.o
b.o: In function `b':
b.c:(.text+0x5): undefined reference to `junk'
collect2: ld returned 1 exit status
make: *** [total] Error 1
--------------------

So b.o compiled as expected with an external reference to junk. However the
linker couldn't find a reference to match it.

Now fixing the problem by dropping the static and readding the include in
a.c produces:
------------------------
cc    -c -o a.o a.c
cc    -c -o b.o b.c
cc -o total a.o b.o

$ total

Junk = 1
Junk = 2
------------------------

Which is the shared expected result.

Static isolates. Static eliminates sharing. So if your compiler is sharing
variables that are declared as static, then something is wrong.

BAJ

2007\10\25@091059 by Dave Tweed

face
flavicon
face
wouter van ooijen <.....wouterKILLspamspam.....voti.nl> wrote:
> > Where and how do we define those variables?
> > My understanding is that they should be declared in main.h so
>
> The magic is in the separation of defining and declaring (iirc the
> correct words):
>
> in the .h: external int foo;
>
> in one of the .c: int foo;
>
> It is the same trick you use (probably without knowning) for functions:
>
> .h:   foo();
> .c:   foo(){...}

For a further refinement along these lines, see Problem #1 here:

  http://www.circuitcellar.com/library/eq/160/index.htm

-- Dave Tweed

2007\10\25@095717 by Alan B. Pearce

face picon face
>For a further refinement along these lines, see Problem #1 here:
>
>   http://www.circuitcellar.com/library/eq/160/index.htm

That is a nice way of doing it Dave.

2007\10\25@101830 by Mark Rages

face picon face
On 10/25/07, Byron Jeff <EraseMEbyronjeffspam_OUTspamTakeThisOuTclayton.edu> wrote:
> On Wed, Oct 24, 2007 at 08:24:06PM -0500, Mark Rages wrote:
> > I define as extern in the header and as static in the C file.  Works
> > fine on the compilers I've used.
>
> That got my Spidey sense tingling. So I had to try it. gcc 4.0.4 on a
> Debian Linux box.

You're right.  I checked my code and I'm not using "static" like I claimed.

Regards,
Mark
markrages@gmail
--
Mark Rages, Engineer
Midwest Telecine LLC
markragesspamspam_OUTmidwesttelecine.com

2007\10\25@124522 by Michael Rigby-Jones

picon face


>-----Original Message-----
>From: @spam@piclist-bouncesKILLspamspammit.edu [KILLspampiclist-bouncesKILLspamspammit.edu]
>On Behalf Of Alan B. Pearce
>Sent: 25 October 2007 14:57
>To: Microcontroller discussion list - Public.
>Subject: Re: [EE] Global variables in projects with many C files.
>
>
>>For a further refinement along these lines, see Problem #1 here:
>>
>>   http://www.circuitcellar.com/library/eq/160/index.htm
>
>That is a nice way of doing it Dave.

The example wasn't very good IMO, it would have made more sense to have shown the GLOBAL macro being applied to data objects rather than functions simply because the 'extern' qualifier is optional for functions. In the vast majority of code I have seen they have not been used, though some coding style guides recommend they are included.

Just to clear up any confusion:

DECLARATION: You are describing the variable or function to the compiler e.g. name, type and scope.
DEFINITION: Allocates memory for the object, defines the actual code for a function.

The rule is DEFINE ONCE, DECLARE MANY i.e. you must only ever define a function or data object once in a project, but you can declare it as many times as you want, though for practical purposes you declare it once in a header file and include the header in multiple C modules.

Regards

Mike

=======================================================================
This e-mail is intended for the person it is addressed to only. The
information contained in it may be confidential and/or protected by
law. If you are not the intended recipient of this message, you must
not make any use of this information, or copy or show it to any
person. Please contact us immediately to tell us that you have
received this e-mail, and return the original to us. Any use,
forwarding, printing or copying of this message is strictly prohibited.
No part of this message can be considered a request for goods or
services.
=======================================================================

2007\10\25@132943 by James Newton

face picon face
And by "static" I meant, of course, "extern"! XP

Static made the Timer1 in flash.c become a different variable (same name,
different memory location) than the Timer1 in main.c.

Extern in all my code, regular definition in flash.c and now the timers are
working.

If it were up to me, I would take Matt's suggestion to keep the variables
private and access them through functions only. That is actually what I had
first proposed when this came up the other day. But the other programmer
involved costs a lot of money and doesn't want to do it that way, so...

Dave's "GLOBAL" define is a really nice solution. For my project, I assume
it would be set up as:

flash.h --
GLOBAL volatile
BYTE Timer1, Timer2;        // 10mS decrement timer


flash.c --
#define GLOBAL
#include main.h
...
#undef GLOBAL

#define GLOBAL extern
#include flash.h


main.c --
#define GLOBAL extern
#include main.h
...
#undef GLOBAL

#define GLOBAL
#include flash.h


Main.h has to be included first in all the .c files, so the extern part is
in different places from the main and flash .c files.

As to the "rule" that .h files only reference and never define, I understand
the desire to keep things separate, but that also then requires that we have
the types of the variables entered the same way in both the .h and .c files.
If it turns out we need a 16 bit timer, with the macros or Dave's GLOBAL
define, we only have to change the one flash.h file from "BYTE Timer1,
Timer2;" to "WORD Timer1, Timer2;" and the compiler will change the
generated code to compensate automatically.

Thanks for all the great education on this point... Someone with the time to
do it should put together a web page...

--
James Newton

{Original Message removed}

2007\10\25@145923 by Peter P.

picon face
dtweed's solution is the most elegant but I favor this (which mostly does the
same thing, but is more explicit):

--header.h--
#ifndef HEADER_H

#ifndef HEADER_C
#define EXT extern
#endif

#define BARLEN 256

EXT int Foo;
EXT char Bar[BARLEN];

void Thisfunc((void*)that);

#ifndef HEADER_C
#undef EXT
#endif

#define HEADER_H
#endif
--header.h end--

--header.c--

#include ...

#define HEADER_C
#include "header.h"
--header.c end--

--other.c--
#include "header.h"
...
--other.c end--

It works fine. Another option is to duplicate the definitions without extern in
a header file with the same name but prefixed with _ e.g. _header.h

Ultimately, it is a question of discipline and makefiles to get things right
imho. When you do not work alone, the header files should have been written
*ages* ago, together with the type definitions and prototypes, imho.

Peter P.


2007\10\25@151530 by Michael Rigby-Jones

picon face


{Quote hidden}

Unless I have missed something this will fail to compile if HEADER_C is not defined, since the EXT symbol will not exist.

#ifndef HEADER_C
#define EXT extern
#else
#define EXT
#endif

Regards

Mike

=======================================================================
This e-mail is intended for the person it is addressed to only. The
information contained in it may be confidential and/or protected by
law. If you are not the intended recipient of this message, you must
not make any use of this information, or copy or show it to any
person. Please contact us immediately to tell us that you have
received this e-mail, and return the original to us. Any use,
forwarding, printing or copying of this message is strictly prohibited.
No part of this message can be considered a request for goods or
services.
=======================================================================

2007\10\25@151928 by Michael Rigby-Jones

picon face


{Quote hidden}

Oops, reposted due to being at work too late and writing gibberish!  I meant to say:

Unless I have missed something this will fail to compile if HEADER_C *is* defined, since the EXT symbol will not exist.

#ifndef HEADER_C
#define EXT extern
#else
#define EXT
#endif

Regards

Mike

=======================================================================
This e-mail is intended for the person it is addressed to only. The
information contained in it may be confidential and/or protected by
law. If you are not the intended recipient of this message, you must
not make any use of this information, or copy or show it to any
person. Please contact us immediately to tell us that you have
received this e-mail, and return the original to us. Any use,
forwarding, printing or copying of this message is strictly prohibited.
No part of this message can be considered a request for goods or
services.
=======================================================================

2007\10\25@170101 by Peter P.

picon face
Michael Rigby-Jones <Michael.Rigby-Jones <at> bookham.com> writes:
> Oops, reposted due to being at work too late and writing gibberish!  I meant to
> say:

> Unless I have missed something this will fail to compile if HEADER_C *is*
> defined, since the EXT symbol will not exist.

Yes, my omission. Your addition is correct:

> #ifndef HEADER_C
> #define EXT extern
> #else
> #define EXT
> #endif

Peter P.


2007\10\25@174615 by Gerhard Fiedler

picon face
Peter Bindels wrote:

> #ifdef FOO_INIT
> #define VAR_DECLARE(var, init) extern var
> #else
> #define VAR_DECLARE(var, init) var = init
> #endif
>
> [header]
> VAR_DECLARE(int a, 42);
> VAR_DECLARE(static int b, 12);
> VAR_DECLARE(volatile int c, 44);
> const int d = 45;
> [/header]

One disadvantage of getting so fancy (that is, so far away from standard C
syntax) is that IDEs that help the programmer out with parsing the code and
supplying all kinds of help with the syntax (like showing the declaration
of a variable in a flyover) often don't understand such declarations. They
have less problems with the form Dave and Peter suggested.

Gerhard

2007\10\26@093118 by Peter P.

picon face
You may find that if the analysis phase is done well you can have somehting like
data.c and data.h where ALL globals and their types are defined (and presented
in a nice sorted way that prevents oopses). The data.h is derived from data.c
and included by everything else (together with something called setup.h and
maybe options.h - the first takes care of portability defined and the second of
compile time options that are not passed on the compiler command line with
CFLAGS (or CDEFS I don't remember which)). In general if you have to tinker with
header
files past a certain point of the mock-up implementation it means that there was
no analysis before it was started. That, in turn, usually indicates that the
debugging will take longer than planned >;-> (evil grin, been there, done that,
both alone and otherwise).

good luck,
Peter P.


More... (looser matching)
- Last day of these posts
- In 2007 , 2008 only
- Today
- New search...