HC08: Global Variables and constants

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

HC08: Global Variables and constants

8,800 Views
bespenschied
Contributor III
I recently changed from V3.2 to 5.0 Codewarrior for the HC08. I am having trouble getting code to compile in the new version that worked in the old. My main code is located in a file called pacer.c. I have global var's that I use in my main routine and other modules called utilities.c and events.c. I put all my global vars and constants in a file called globals.h
 
I now get duplicate definitions when I include the globals.h file in the utilities.c module. If I do not include the globals.h file in the utilities.c module I get not declared errors for the variables. I have been programming C for a few years now and still seem to have troubles with this. I have checked all my books and reference material and I keep getting different answers. Some say the vars have to be declared as external in the header file and declared as just the type in the module they are used in. Then others say just the opposite. It works better in codewarrior if I use only the type as byte, int, etc in the header file (globals.h) and the extern in the module it is being used in. Is there a general discussion on this somewhere. I do not mind the research. I just cant figure out what is the correct (ANSI) method. Here is a cop of my globals.h file
 
#ifndef __globals
#define __globals
// Global variables
unsigned int Delay10ms;
byte WaitTime;
byte ProgramCount;
byte Level;
byte key;
byte Count2Sec;
byte kb_flag; //used to indicate keyboard status
byte keyval; //Value of pressed key
//setup for the different Modes used in the program
byte Mode;
#define run   0          /* Run Mode        */
#define program  1          /* Program Mode        */
#define sleep  3   /* Sleep Mode */

#define Key_Mode  1   /* Keyboard Value for mode switch */
#define Key_Up   2   /* Keyboard Value for Up switch */
#define Key_Down  4   /* Keyboard Value for Down switch */
#define Key_Standby 8   /* Keyboard Value for program switch */

#endif //__globals
Any ideas? Thanks!
 
BCDE

Message Edited by CrasyCat on 2007-04-13 02:20 PM

Labels (1)
Tags (1)
0 Kudos
19 Replies

2,343 Views
sjmelnikoff
Contributor III
Hi.
 
Just to put a slightly different perspective on this issue, it can be helpful to think of the variable definition as the equivalent of a function body, and the declaration as its prototype.
 
A function body appears in just one .c file, while its prototype appears in one .h file but can be #included multiple times. Similarly, a variable definition (which may include an initialiser) may only occur in a single .c file, while its declaration (which must include the "extern" keyword) will typically occur in a single .h file and be #included as necessary.
 
To comment on a couple of the suggestions put forward in this thread, we use MISRA-C, which does not recommend (a) putting definitions in .h files, and (b) using #undef.
 
So to summarise, the way we would declare, define and use a global variable is as follows:
 
Global.h:
 
#ifndef GLOBAL_H
#define GLOBAL_H
.
extern u8 Global_u8MyVar; /* declaration */
.
#endif
 
Global.c
 
#include "Global.h"
.
u8 Global_u8MyVar = 0; /* definition + optional initialisation */
 
MyFile.c
 
#include "Global.h"
.
void MyFile_MyFunc(u8 u8MyOtherVar)
{
  Global_u8MyVar = u8MyOtherVar + 1; /* use */
} /* MyFile_MyFunc */
 
Steve M.
 
0 Kudos

2,343 Views
Pyretta
Contributor I

I am still completely not getting this. What used to be easy in just creating a library file with extern blah and then including that library file in my main C program and being able to call that variable in all of my other C files, has turned into this  L1818 duplicated in file1.c and file2.c

 

I have a file adc.h that has the following

//start of adc.h

#ifndef __adc
#define __adc
extern  int state;
extern  unsigned long adclow=0;   // store a/d low 8 bits
extern  unsigned long adchigh=0;  // store a/d high 8 bits
extern  unsigned long adcRTD=0;   //store a/d RTD total in decimal
extern  unsigned long adcR=0;     //store a/d Resistance total in decimal
extern  int RTD_Read_Times = 0;
extern  float RTD1;
#endif

//end of adc.h

 

I have a file adc.c that has the following include

//start of adc.c

#include "adc.h"

 

float adc_to_tempC(int test) {

            switch(state) {

            case 0: break;

            default : break;

            }

}

//END of adc.c

 

 

I have a main.c file that has the following

#include "adc.h"

 

void main{

 state++;

}

 

When I compile, it will tell me about all the duplicate extern variables that are in adc.h.

 

Link Error   : L1818: Symbol 14 - adclow duplicated in adc.c.o and main.c.o


Link Error   : L1818: Symbol 15 - adchigh duplicated in adc.c.o and main.c.o


Link Error   : L1818: Symbol 16 - adcRTD duplicated in adc.c.o and main.c.o


Link Error   : L1818: Symbol 17 - adcR duplicated in adc.c.o and main.c.o


Link Error   : L1818: Symbol 18 - RTD_Read_Times duplicated in adc.c.o and main.c.o


Link Error   : L1301: Cannot open file C:\my freescale projects\SetTime&Temp\Demo_Data\Standard\ObjectCode\adc.c.o


Link Error   : Link failed

 

 

If I remove the #include adc.h from main, it will tell me it does not know what these variable are. Obviously the program I posted above has been lopped off so that I can show what I have here. I can assure you that in my main.c file, I do not have even 1 reference to adclow. I use the variable state as a switch for reading the ADC that is used in adc.c that I need to keep track of.

 

 

 

 

 

0 Kudos

2,343 Views
CompilerGuru
NXP Employee
NXP Employee

A declaration cannot have a initial value. If a variable has one, it is always a definition, even if there is a extern keyword.

So;

>extern  unsigned long adclow=0;

is just the same as

>unsigned long adclow=0;

 

The header file should contain only:

// adc.h

>extern  unsigned long adclow;

 

And in adc.h, the variable should be defined:

 

// adc.c

>#include "adc.h"

>unsigned long adclow=0;

 

This means that the variable is listed at two places, once as declaration in the header with extern and with no initialization value, and once as definition in the c file.

 

Daniel

 

0 Kudos

2,343 Views
Lundin
Senior Contributor IV

You get the linker error because you are trying to initialize extern variables. Initialization must be done where the variable is actually declared (allocated).

 

---

 

Note the following:

- If you are using the ANSI option of Codewarrior, i.e. standard C, you don't need to initialize global variables to zero. All global variables are implicitly initialized to zero in the C language.

 

- It it considered bad programming to use global variables for many reasons. There are only two cases where you might need to declare global variables: When they are hardware registers, or when you have extreme demands on variable access time in performance-critical parts of a realtime system. In all other cases you shouldn't use extern/global variables, but instead use private encapsulation with set/get functions (that can be inlined).

 

- In embedded programming with systems that have non-volatile memory, you should avoid initialization of statics/globals entirely, because some non-standard compiler might remove initalization at startup to increase performance. Instead, set the variables in runtime before they are used.

0 Kudos

2,343 Views
isionous
Contributor III

This is how you want to handle the global variables of a module:

 

 

//file: SomeModule.h ---------------------#ifndef SOME_MODULE_H#define SOME_MODULE_H//declare public global variablesextern int SomeModule_Var1;extern int SomeModule_Var2;//declare public functionsvoid SomeModule_Init(void);#endif//file: SomeModule.c ---------------------#include "SomeModule.h"//define public global variablesint SomeModule_Var1;int SomeModule_Var2;//define private global variablesstatic int PrivateVar1;//declare private functionsvoid privateFunction(void);//implementation of public and private functionsvoid SomeModule_Init(void){    SomeModule_Var1 = 0;    SomeModule_Var2 = 0;    PrivateVar1 = 0;}void privateFunction(void){    PrivateVar1++;}//file: main.c ---------------------#include "SomeModule.h"void main(void){    SomeModule_Init();    SomeModule_Var1 = 3;}

 

Public global variables are declared (use extern) in header file.  Public and private global variables are defined (do not use extern) in the c file.  Everyone who wants to use your public variables and functions includes the header file.  Remember that a #include statement merely replaces the statement with the text of the specified file.

 

0 Kudos

2,343 Views
bespenschied
Contributor III
Steve,

From your summary, when does Global.c ever get used? and if I had a utilities.c file how would I Include the global declarations in it?

CrasyCat,

Thanks, It makes sense knowing that the __ commands are not global and only exist in the current compilation unit. That is why my original attempt did not work.

From your example:

#undef __globals
#include "globals.h"

In all other C modules you need to get
#define __globals
#include "globals.h"

What does this do? Does it make the __globals visible in all units?
0 Kudos

2,343 Views
sjmelnikoff
Contributor III


bespenschied wrote:

From your summary, when does Global.c ever get used? and if I had a utilities.c file how would I Include the global declarations in it?


If you think of the global variable as being a bit like a global function, the purpose of Global.c is to allocate space for the variable (analogous to a function definition), while the purpose of Global.h is to announce that the variable exists and can be used (analogous to a function declaration).
 
Global.c is "used" whenever any other module accesses the global variable.
 
The global variable can be used in utilities.c simply by #including Global.h, as illustrated in the example in my earlier post.
 
Steve M.
0 Kudos

2,343 Views
bespenschied
Contributor III
Thanks for all the help. It makes sense now. I hope others have gained some insite to this confusion also.
0 Kudos

2,343 Views
CrasyCat
Specialist III
Hello
In fact the idea is to have __globals undefined when building one source file in the application and to define it for all other compilation units.
 
So when you are writing:
#undef __globals
#include "globals.h"
 
Variables will be defined
(unsigned int Delay10ms;
byte WaitTime:smileywink:
 
When you write
#define __globals
#include "globals.h"
 variables will be declared
(extern unsigned int Delay10ms;
extern byte WaitTime:smileywink:
 
So you need to have the line #define __globals prior to each #include "globals.h" statement in all source file except one (the one where th definition should take place.
 
CrasyCat
0 Kudos

2,343 Views
bigmac
Specialist III
Hello bespenschied,
 
I assume that your globals.h file is included near the start of your pacer.c file.  This would provided the declaration for the global variables.  However, when you use some of these variables within the file utilities.c, they need to be declared as external within that file.
 
Modifying the globals.h file in the following manner might also work -
 
#ifndef __globals
#define __globals
// Global variables
unsigned int Delay10ms;
byte WaitTime;
 
#else
extern unsigned int Delay10ms;
extern byte WaitTime;
 
 
#endif //__globals
 
A short discussion on global variables is given in the attached document.
 
Regards,
Mac
 

Message Edited by bigmac on 2006-06-07 04:11 PM

0 Kudos

2,343 Views
SteveRussell
Contributor III

To really understand the way C documentation describes these things, you need to keep in mind the difference between a definition and a declaration.

A declaration just gives C just enough information to correctly reference a variable or function.

A definition creates a definite place for a C variable or function and completely describes it. It includes all the information in a declaration, but has the additional information of the variable initial value or a function body

One of the reasons for the confusion in the documentation is that C will automatically create an instance of an extern variable which has no definition, just several extern declarations. The feature is one of those historical parts of C that still works, but is no longer recommended for use.

A slightly different convention, which seems to give better documentation is to have the "globals.h" file of the form:

#ifndef __globals #define __globals
 
// Global variables, declarations
exterm unsigned int  Delay10ms;
extern byte          WaitTime;
 
#endif //__globals
 
And a globals.c file of the form:
 
#include "globals'h"
 
// Global variables, Actual definition
unsigned int Delay10ms = 10 ;
byte         WaitTime  = 5 ;
 
As the program gets larger, you can share variables between several modules in a program without making them truly global.  This is done in a similar style.  In this case it is common to place the actual definition in some module that "owns" the variables.
 
The modules using the variables are easily identified by the presence of the include file that contains the declarations.
 
0 Kudos

2,343 Views
bigmac
Specialist III
Hello Steve,
 


Steve Russell wrote:

A definition creates a definite place for a C variable or function and completely describes it. It includes all the information in a declaration, but has the additional information of the variable initial value or a function body


So the difference between a declaration and a definition would seem to be a moot point for simple global variables that use implicit (default) initialisation to zero.

Regards,
Mac

 


0 Kudos

2,343 Views
SteveRussell
Contributor III


bigmac wrote:

Hello Steve,
 


Steve Russell wrote:

A definition creates a definite place for a C variable or function and completely describes it. It includes all the information in a declaration, but has the additional information of the variable initial value or a function body


So the difference between a declaration and a definition would seem to be a moot point for simple global variables that use implicit (default) initialisation to zero.

Regards,
Mac

Not if you want a non-zero initial value.

My main point was that you will get extra confused when reading C specifications and discussions if you don't appreciate the difference between declaration and definition.

I confess, I don't remember exactly why the use of the implicit initialization is discouraged by some authorities.





0 Kudos

2,343 Views
bigmac
Specialist III

Hello Steve,

I am still a little confused over the declaration/definition issue for global variables.  Let's assume that we only have one file, say main.c.  From your previous comments, I presume that the following code would be necessary, outside of any function, to declare/define a single global variable global_var1.

int global_var1;     // Declaration?

int global_var1 = 0; // Definition?

void main(void)
{

etc.

Is this the correct interpretation of your previous explanation?  Is it also allowable to combine the declaration and definition as a single assignment?  Now I would assume that both the declaration and definition can only occur once in a program (there can only be a single initial value).

However, if we now add a second file that references the same global variable, I have previously understood that we need to tell the compiler to look for the declaration of the variable elsewhere.  So the new file would need to include the following prior to first use of the variable, and this would occur for all additional files that use the variable:

extern int global_var1;

Is this correct?  I am not sure whether this counts as a declaration, a definition, or something completely different.

Clarification of these simple cases would give a fuller understanding of more complex cases, such as global structures.

Regards,
Mac

 

0 Kudos

2,343 Views
SteveRussell
Contributor III

Mac,

I'm sorry, I should have given some examples.

I was trying to give informal definitions of the terms.  Look "declaration" and "definition" up in you favorite C book  for different wording. 

A declaration just gives C just enough information to correctly reference a variable or function.

As in:

Code:

extern int foo;             // declaration    double sin( double arg ) ;  // declaration

 

The compiler gets enough information to reference the variable or function, but it is up to the linker to find where the actual variable or the function body is.
 
A definition creates a definite place for a C variable or function and completely describes it. It includes all the information in a declaration, but has the additional information of the variable initial value or a function body

Code:

int foo ;    // definition tells compiler "put foo here"// definition tells compiler "put the sin function here,// with this definitiondouble sin( double arg ) { /* much code */} ;


 

Actually gives the storage location or the function body.


bigmac wrote:

Hello Steve,

I am still a little confused over the declaration/definition issue for global variables.  Let's assume that we only have one file, say main.c.  From your previous comments, I presume that the following code would be necessary, outside of any function, to declare/define a single global variable global_var1.

int global_var1;     // Declaration?

Actually a definition without an initializer given.

int global_var1 = 0; // Definition?

Yes, also a definition

void main(void)
{

etc.

Is this the correct interpretation of your previous explanation?  Is it also allowable to combine the declaration and definition as a single assignment? 

You can't avoid it.  A definition includes all the information in a declaration, and more

Now I would assume that both the declaration and definition can only occur once in a program (there can only be a single initial value).

Its good practice to have only one declaration for an item in a module, but many are allowed, if they all agree.

So, for example if you have a declaration for a function in a header file, it is helpful to include that header file in the module that defines the function.  The compiler will report an error if the header file declaration doesn't match the definition.

You can only have one definition of something global in a program.

However, if we now add a second file that references the same global variable, I have previously understood that we need to tell the compiler to look for the declaration of the variable elsewhere.  So the new file would need to include the following prior to first use of the variable, and this would occur for all additional files that use the variable:

extern int global_var1;

You are correct. This is indeed a declaration



 

0 Kudos

2,343 Views
bespenschied
Contributor III
I started this thread in June and am just now getting back to read all the other posts. I have ADD and often get sidetracked.....

Anhow I really appreciate all the discussion on this topic that all of you gave. It didn't make sense why I had to treat the definitions different depending on which module was using it. bigmac's example makes sense but did not work. I still got an error saying the symbol was duplicated.

#ifndef __globals
#define __globals
// Global variables
unsigned int Delay10ms;
byte WaitTime;

#else
extern unsigned int Delay10ms;
extern byte WaitTime;


#endif //__globals

Does the #define __globals command give __globals a value that remains active during the whole compiling process or just the current file? When I changed my code as above, it appears that the __globals is undefined when it gets used by the main.c (the first module to call it) and it uses

unsigned int Delay10ms;

to define the Delay10ms global Value and the __globals is now defined. When the 2nd module calls it, utilities.c, I would think the __globals is now defined and should use

extern unsigned int Delay10ms;

to define Delay10ms. If this was the case I should not be getting the error:
L1818: Symbol 14 - Delay10ms duplicated in Utility.c.o and PacerV1.3.c.o
L1818: Symbol 15 - WaitTime duplicated in Utility.c.o and PacerV1.3.c.o

I did what I thought Steve Russel suggested and created 2 files. In the globals.h file I put:

#ifndef __globals
#define __globals
// Global variables
unsigned int Delay10ms;
byte WaitTime;
#endif //__globals

In the globals.c file I put:
// Global variables
extern unsigned int Delay10ms;
extern byte WaitTime;

I use

#include "globals.h"

in my main.c module and I use

#include "globals.c"

in all modules that need the global variables. This method works but makes it necessary to edit 2 files every time I need to change any Global variables.

Sten's example using #define ALLOC 1 worked but again means remembering to add the #define ALLOC 0 to all modules that need the Global vars.


Thanks again.
0 Kudos

2,343 Views
CrasyCat
Specialist III
Hello
The #define __globals command is valid only for the current compilation unit. A compilation unit is a source file and all the header files included there.
 
So when you build utility.c, the macro __globals is undefined again.
 
In order to be able to build your application you have to get following code in main.c:
 
#undef __globals
#include "globals.h"
 
In all other C modules you need to get
#define __globals
#include "globals.h"
 
CrasyCat
0 Kudos

2,343 Views
Sten
Contributor IV

One way to make handling of global variables easier is to use the following approach:

Code:

in globals.h#if ALLOC#define GLOBAL#else#define GLOBAL extern#endifGLOBAL char global_variable;
GLOBAL int  another_global_variable;


 
Code:

in main.c#define ALLOC 1#include "globals.h"


 
Code:

in the rest of the c-files#define ALLOC 0#include "globals.h"


 

0 Kudos

2,343 Views
bespenschied
Contributor III

Thanks for the help. I will read the document and try your suggestions. I also figured out that when you put constants like #define run 0 in the same header file as globals this causes problems because they are handled differently when compiled. I split the 2 up and now have a constants header file and a globals header file. It seemed to stop the errors I was getting.

Thanks!

Brian

 

0 Kudos