I am attempting to define a set of global variables which will configure my device, about 10 in a dedicated .c file, that will be changed on a regular basis at compile time (as per device requirements), I want these to be in this separate file so they can all be changed easily. These variables are then called throughout my program in various files. And are never changed only read. The problem is that my compiler (XC8 for PIC MCU's) doesn't define the variable, as it can only see that one use of the variable in the file, even though it is called with extern throughout the program.
config.h
unsigned int Global_A;
unsigned int Global_B;
void config(void);
config.c
void config(void)
{
unsigned int Global_A=987;
unsigned int Global_B=123;
}
prog_a.h
extern unsigned int Global_A;
extern unsigned int Global_B;
unsigned int var_A;
void prog_a(void);
prog_a.c
unsigned int var_A=0;
void prog_a(void);
{
var_A=Global_A+Global_B;
}
main.c
#include config.h
#include prog_a.h
void main(void)
{
while(1)
{
config();
prog_a();
}
}
as a result, the equivalent var_A is always 0, as the compiler has done away with config.c as it cannot see the variable called again.
I'm assuming the answer is very obvious to those more versed, but I can't find anything online. I have not had any trouble with using extern and globals before when they are used in the file the are defined in. But I could just be using it wrong fundamentally, so feel free to berate me.
Thanks in advance.
p.s if it wasn't obvious this is an example code to illustrate my problem.
Your function config declares two new variables in the scope of the function (their names hide those of the global variables). They don't exist anywhere outside of it, and assigning a value to them does nothing. If your goal was for it to initialize the globals, you need do this:
// config.h
extern unsigned int Global_A;
extern unsigned int Global_B;
void config(void);
// config.c
unsigned int Global_A;
unsigned int Global_B;
void config(void) {
Global_A=987;
Global_B=123;
}
With extern keyword it it necessary to declare the variable once (preferably in a header file) define it once in a .c file that has visibility to the declaration statement. That is it. Where the extern defined variable is necessary, #include the header file in which the declaration statement occurred.
Also note it is important also to define extern variable(s) in global scope (i.e. not in a function).
config.h:
#include "prog_a.h"
//unsigned int Global_A;
//unsigned int Global_B;
void config(void);
main.c
#include config.h
#include prog_a.h
...
//suggest defining these here:
unsigned int Global_A=0;//define outside of function
unsigned int Global_B=0;
...
config.c
#include "prog_a.h"
...
void config(void)
{
Global_A=987;
Global_B=123;
}
Your global variables are all of type int, so why not just use #define?
Change file config.h to
#define Global_A 789
#define Global_B 123
You do not actually have to declare any int variables to hold those values, plus, they will be const and unmodifiable.
That's they way that we did it "back in the day", but in the last decade or two, I see more and more actually storing these configuration values in an external text file
It can be a .INI, or XML or JSON, etc, etc, that is up to you.
You just create different files, let's say Singapore.ini and Paris.ini and Auckland.ini, etc, each containing a key/value pair.
e.g
time_zone = X
population = Y
etc, etc
Then, at the start of your main, read the file in and store the values -but not in globals, which are frowned upon, these days. Read them into variables which are local to config.c, and have config.c/h provode methods to read their values, e.g GetTimeZone() and GetPoulation(), etc
Don't worry about any code size or run time impact of this, as any decent compiler will in-line these function calls.
One advantage to reading "global" configuration values in an external text file is that you only need to build your software once. You do not need to rebuild and have an executable for each configuration, which the road that you are currently heading down.
Firstly, this makes it easier to test your software (especially automated test), by merely editing the text file, or supplying a new one.
Also, since you only have a single executable, you can ship that to all of your users/customers, and give each a tailored config file. You can totally control & change the functionality of your software just by changing the config file. You might want to think about that.
Related
Alongside main.c file, I have following my_custom_data_structure.c file in my project. My my_custom_data_structure.c file contains a lot of variables, functions, etc.
I am using #include "my_custom_data_structure.c" directive in main.c.
Problem
I would like to import only single function called foo from my_custom_data_structure.c. I don't need all the variables and functions, which are declared in my_custom_data_structure.c file.
Any insights appreciated.
File structure
-
|- main.c
|- my_custom_data_structure.c
Content of my_custom_data_structure.c
#include <stdio.h>
int DELAY = 20;
int SPEED = 7;
char GRANULARITY_CHAR = 'g';
unsigned int RANGE = 3;
void foo(){
// TODO: In future, this function will print SPEED.
printf("foo works!");
}
/*
The rest of this file is filled by a lot
of code, which is not needed for main.c
*/
Content of main.c
#include <stdio.h>
#include "my_custom_data_structure.c"
int DELAY = 3;
int main(){
foo();
printf("Delay is %d", DELAY);
return 0;
}
UPDATED: Added working example
The usual way is to compile them separately. So you have your main.c, and your extra.c, and you should create a extra.h (and include it in main.c).
In this extra.h, put in declarations for anything that is to be exported from your extra.c file.
For example any functions that should be available to other files. All other functions should be declared/defined only in your extra.c as static, so that they are not available as symbols to be linked when main.c is compiled.
Normally, you don't include source files (.c) inside other source files (or inside headers). It's possible (and occasionally necessary), but it isn't usual.
Unless you've designed the my_custom_data_structure.c to allow you to specify which functions are to be compiled, you get everything in the file. For example, you could use:
#ifdef USE_FUNCTION1
void function1(void *, …)
{
…
}
#endif /* USE_FUNCTION1 */
around each function, and then arrange to
#define USE_FUNCTION1
before including the source, but that's not usually a good way of working. It's fiddly. You have to know which functions you use, and which other functions those need, and so on, and it is vulnerable to changes making the lists of USE_FUNCTIONn defines inaccurate. Of course, the source code might have blocks of code like:
#ifdef USE_FUNCTION1
#define USE_FUNCTION37
#define USE_FUNCTION92
#define USE_FUNCTION102
#endif /* USE_FUNCTION1 */
so that if you say you use function1(), it automatically compiles the other functions that are required, but maintaining those lists of definitions is fiddly too, even when the definitions are USE_MEANINGFUL_NAME instead of a number.
Create a header (my_customer_data_structure.h) declaring the functions and any types needed, and split the implementation into many files (mcds_part1.c, mcds_part2.c, …).
Compile the separate implementation files into a library (e.g. libmcds.a), and then link your program with the library. If it's a static library, only those functions that are used, directly or indirectly, will be included in the executable.
I have 2 files: Sod/iload/iload.c and
Item/itemrule/itemrule.c, and I want to access a variable defined in iload.c which is defined in itemrule.c.
To do this, I made and defined a global variable in iload.c, and I tried to access this variable in itemrule .c with the extern keyword, but it is always 0.
I'm worried that it might be because the files have different paths, does anyone know how I can access this variable?
The usual idiom is to use an extern declaration in a header file and include that wherever the global is needed.
// foo.h
// Make the global visible in any C file that includes this header.
extern int my_global_var;
// foo.c
#include "foo.h" // Not really needed here, but fine.
int my_global_var;
...
// bar.c
#include <stdio.h>
#include "foo.h" // This one makes the global visible in the rest of the file.
void do_something(void) {
printf("my global var's value is: %d\n", my_global_var);
}
Note that using globals like this in a program of any significant size or complexity can lead to messy, bug-prone, and hard-to-change code. Not a great pattern to follow.
I would like to offer an alternative to Gene's answer. In my experience there are two main ways to share variables across modules (compilation units):
1) "Getters and Setters".
2) Externs.
Depending on what kind of team you're working with, they'll have a preference for one or the other. C functions by default have external linkage; you need to force internal linkage via the static keyword in front of the function name if you don't want this.
1) Getters and Setters:
// foo.c
#include <stdio.h>
int my_global_var = 0;
...
Then you can follow it with externally-linked getters and setters. i.e.:
int get_my_global_var(void)
{
return my_global_var;
}
void set_my_global_var(int var)
{
my_global_var = var;
}
This is done within the c file (module). It will be the getters and setters will be able to be called from any other module and they will get and set the global variable my_global_var.
2) Externs:
// foo.c
#include <stdio.h>
int my_global_var = 0;
...
An alternative to getters and setters is to use externs. In this case you add nothing extra to the module that contains the global variable you wish to access/modify (my_global_var).
// bar.c
#include <stdio.h>
extern int my_global_var;
...
Notice the syntax here; when we use the extern keyword, we don't initialize it as anything. We are simply infoming the compiler that the global variable my_global_var has external linkage.
Scoping in C is confusing as hell. I have a variable: "int qwe". This var should be visible in one or more files - f1.c in this case, but not the another f2.c .
Say i have: main.c, f1.c, f2.c, header.h
main:
call f1();
call f2();
header:
#ifndef HEADER_INCLUDED
#define HEADER_INCLUDED
int qwe = 1;
void f1();
void f2();
#endif // HEADER_INCLUDED
f1.c:
#include <stdio.h>
extern int qwe;
void f1(){
printf("In f1: %d\n", qwe);
}
f2.c:
#include <stdio.h>
static int qwe = 2;
void f2(){
printf("In f2: %d\n", qwe);
}
Now this gets confusing. There is definition and declaration. I have defined qwe in the header, declared it in f1.c. Is that correct? Should definition happen in header and declaration in f1.c instead? I tried the latter case, but got an error - "multiple definition of qwe". When i removed the #include directive from f1.c, it worked... It also works when i remove the extern keyword. Is extern redundant?
f2.c i guess it's ok and behaves as expected, or is it? But if i put an #include with header, it breaks. Why is that?
When should i use #include in source files? If i don't include it f1.c or f2.c it works...
Also, if i define a variable as static inside a function, like static int i = 0; This variable will not be destroyed when function exist, it will keep it's memory and data. And next time that same function gets called, will have access to it, right? But the var won't be reinitialized to 0, i.e. the line where is defines won't execute. Correct?
Life stomps me :(
In the header, declare the variable. In e.g f1.c, define the variable, e.g. int qwe = 1; // at global scope.
In all files that want to see/change qwe, include the header that declares the variable. Easy-peasy.
You need to declare the variable in the header, and define it in one and only one C file.
In C, you cannot have a variable that doesn't "belong" to a given translation unit (source file). So it must be defined by exactly one translation unit in the whole program.
When you declare a variable as extern, you're telling the compiler the symbol is (possibly) external to your translation unit (c file).
It's probably also worth noting that when you try to declare a variable without extern, the variable is also defined, e.g.:
/* Declares, but does not defines external symbol 'foo' */
extern int foo;
/* Both declares AND defines bar */
int bar;
This is also different from how functions work to where the "default" syntax for declaration does NOT define a function:
/* Declare, but don't define spam */
void spam(void);
/* Declare, but don't define eggs */
extern void eggs(void);
/* Declare & define 'cheese' */
void cheese(void){ return; }
So your example should look more like this:
qwe.h:
#ifndef QWE_H
#define QWE_H
/* Declare qwe here */
extern int qwe;
#endif
f1.c:
/* DEFINE qwe here */
int qwe = 1;
f2.c:
#include "qwe.h" /*header includes the `extern int qwe` declaration */
void my_function(void)
{
/* use external symbol here! */
qwe = 10;
}
The scoping system isn't that confusing. The rule is this:
if you define something in a .c file EVERY other .c file in your program can access it (it is put in the global namespace).
if you specify static in front of its definition then only things in the SAME file can see it. This should be your default position for all functions and variables you don't want other .c files to be able to access.
It is very important to remember that extern only tells the compiler that the variable/function in question is not defined in the current file. This prevents the compiler for otherwise issuing an error because it can't find the symbol, but it has nothing to do with scoping - your .c file sees everything in the global namespace and if you have not followed the second part of the rule you will quickly find out about this at link time.
Header files similarly have nothing to do with scoping. They are just convenient places to put a bunch of extern statements and macros.
In C, you should use the header file in general to declare the data but not define the data. You don't want to define global data in a header because it will then be redundantly defined in multiple modules. The header indicates to multiple modules the existence of some data or function somewhere and what its type is, as well as common constants and macros (#defines). Outside of that, things in C are very simple. Just about anything is, technically, global unless you declare it static, keeping it scoped to the module it's defined in. The extern declarations for data in the headers and the function prototypes help the compiler know that these items are being accessed by a particular module and what the data types are for access so that the correct code can be generated.
You have:
Two functions f1 and f2 that are defined in separate modules but used in main. So these need to be declared in a header file.
A global data item qwe being used in more than one module.
A static qwe used in one module.
Assuming you want this done with one header file (you might need separate ones for f1, f2, and global data - see below), you could set up
your header as:
#ifndef MY_HEADER_H
#define MY_HEADER_H
extern int qwe;
void f1(void);
void f2(void);
#endif // MY_HEADER_H
Then in your main.c:
...
#include "my_header.h"
int qwe; // This is global and can be accessed from other modules
void main(...)
{
// call f1
// call f2
...
I just defined the global variable, qwe, in main.c arbitrarily. If you have a few globals, you can define them in their own glob_data.c module, for example, and have it's own header, glob_data.h, to declare them. Any other module that needs to access them would include the glob_data.h header so that compilation can properly be done on that module to access that data. Keeping the global data in separate headers helps with cases like you have where you have a static instance of the data versus the global, which are in conflict. You can avoid including the data header file for that global item when you want to compile with the static item.
Then in your C file, f1.c:
...system headers included...
#include "my_header.h"
void f1() {
printf("In f1: %d\n", qwe);
}
And in f2.c:
...system headers included...
#include "my_header.h" // Only if it doesn't contain `extern int qwe;`
static int qwe = 2; // This hides the global qwe and is known only
// to f2.c
void f2(){
printf("In f2: %d\n", qwe);
}
As I mentioned above, you might want to separate your function prototypes and your global data declaration in separate headers. That way, you can include only what's needed in each module and avoid conflicts, such as when you have a static int qwe; versus the global int qwe;.
I have defined qwe in the header, declared it in f1.c. Is that correct?
No, it should be the other way around. You are supposed to have a definition of a global variable in a single translation unit (that's geek speak for a .C file) but you may declare it in as many translation units as you wish. Since headers potentially get included from many translation units, declarations go in the headers.
When should i use #include in source files?
You do it when the header has anything that is needed for your translation unit to compile, with very few exceptions. Note that in some situations it may be necessary or desirable to make a forward declaration manually without including the header.
Also, if I define a variable as static inside a function, like static int i = 0; This variable will not be destroyed when function exist, it will keep it's memory and data.
That is correct, the static variable inside the function will be assigned the initial value only once, and retain the value that you assign to it for as long as your program continues to run.
I needed to define several variables (Global variables), which are going to be used by many .c files. Variables like String array, File Pointer, Int etc.
Situation : FileX.h
Different c files(FileA, FileB, Filec, FileD) compiled with -c option individually(FileX.h have been included by all) then some of the files compiled again by combining them. When these are compiled individually No error pop up, but When they are compiled in a group (FileA.o, FileB.o and FileC.o), It pop ups Error. Is there any way to solve it. I thought of solving this with extern but seems this would also pop up error also.
Any suggestion please ?
I don't want to define variable in each .c file
I have String array so i don't want to define them every file
I'm assuming you get a multiple definitions error because your header looks like
global_variables.h
int global_a = 10;
int const global_b = 20;
What you need is
global_variables.h
extern int global_a;
extern int const global_b;
global_variables.c
int global_a = 10;
int const global_b = 20;
Edit: Further explanation:
Now in all your other files that need the global variables all you need is:
other_file.c
#include "global_variables.h"
void some_func(void){
global_a = 5; /* ready to use */
}
other_awesome_file.c
#include "global_variables.h"
/* and now you can use all globals */
I have two files:
hudwidgets.c
#include "osd.h"
#include "osdadd.h"
#include <stdio.h>
struct TextSize tsize;
char buff[50];
void hud_draw_lin_compass(int cx, int cy, int tick_maj, int tick_min, int range, int heading)
{
.. important code that uses buff ..
}
hud.c
#include "hudwidgets.h"
#include "hud.h"
#include "osd.h"
#include "osdadd.h"
.. some code ..
void hud_rc_plane_single_frame()
{
fill_mem(0x0000);
if((frame / 50) % 2 == 0)
{
get_next_warning(buff);
}
.. some more code ..
}
The problem I have is that when I try to compile this, the compiler complains of no buff defined, but when I try to define it, the linker complains of two buff variables. Catch-22. To this end, I am asking two questions:
how to fix this, and;
if it is possible to use the same variable thus saving memory because only one variable needs to be allocated (working with a memory constrained microcontroller.)
You need this in the top of hud.c, and any other .c file you use them from:
extern struct TextSize tsize;
extern char buff[50];
The extern keyword tells the compiler that the "actual" variables already exist, in some other unit (file), and the linker will fix it all up for you in the end.
If you're doing this on a large scale in a project, consider how you might encapsulate globals in one place, and create a shared .h file that declares these things as "extern" for all the places that you use them from.
use "extern char buff[50];" in the files where you have not initialized the buff and want to use it. This tells that the declaration is done in other files and you are using it in this file.