Most elegant way to share a C array - c

I have to turn back to (embedded) C after some lengthy time with C++, and have the following problem:
I have a source module which is included a lot of times, let's call it utilities.h and utilities.c
In it, I have an important array, let's call it
#define IMPORTANT_ARRAY_LENGTH 10000
char important_array[IMPORTANT_ARRAY_LENGTH];
I have a lot of other functions in this utilities module, and they all work fine. However, in one of the other source files, let's call it worker.c, I have to use this array. What is the "official", elegant way to do this, without having to put extern char important_array[IMPORTANT_ARRAY_LENGTH] and the macro definition in the worker.c ?
If I do the following:
utilities.h
#ifndef _UTILITIES_H_
#define _UTILITIES_H_
#define IMPORTANT_ARRAY_LENGTH 10000
extern char important_array[IMPORTANT_ARRAY_LENGTH];
// ...
utilities.c
#ifndef _UTILITIES_C_
#define _UTILITIES_C_
#include "utilities.h"
char important_array[IMPORTANT_ARRAY_LENGTH];
// ...
worker.c
#include "utilities.h"
// ...
important_array[0] = 0;
then my array will be an undefined symbol in worker.c. If I don't use the extern keyword in utilities.h, then of course, it's a duplicate symbol. (Strangely, it compiles with just a warning, and I can see from the linker file that the size is allocated multiple times.)
Do I really have to declare my array in worker.c? I want to keep everything clean, and have all declarations in one place only: in a header file. And I want to have the macro definition only once (this is secondary, because I could use a const, but I want the preprocessor to handle it, and not take up place)

What you have is the canonical way to do it: have an extern declaration in the header file, and define the variable in the .c file.
my array will be an undefined symbol in worker.c
No, it won't. Your code will compile and link just fine.

I often put the definition in the header (this is frowned upon, I know).
It keeps the definition and declaration close together, which is a Good Thing.
/* file.c */
#define FILE_C 1
#include "file.h"
.
/* file.h */
#ifndef FILE_H
#define FILE_H 1
#define BIG_SIZE 13
#if FILE_C
char the_array[BIG_SIZE];
#else
extern char the_array[BIG_SIZE];
#endif
#endif /* FlLE_H */
.
/* other_file.c */
#include "file.h"
There is no risk of doing it wrong: the linker will complain if you do it wrong.
BTW a similar way to basically do the same, but maybe a bit more readable, is:
/* file.h */
#ifndef FILE_H
#define FILE_H 1
#if FILE_C
#define EXTERN /**/
#else
#define EXTERN extern
#endif
#define BIG_SIZE 13
EXTERN char the_array[BIG_SIZE];
...
#undef EXTERN
#endif /* FlLE_H */

Having one declaration (extern...) in each translation unit and exactly one definition is the most elegant way to do this.
So leave the extern char important_array in the header and char important_array in one of the .c files.

Create a new function at utilities.c called something like "get_important_array" that just returns a pointer to array and put the prototype at utilities.h. After that, when you put the utilities.h at worker.c you'll have important_array access in a simple, and organized way.

Related

C circular dependency with headers

I am working on a project where I have to follow guidelines on the organization of the files and I can't get it to compile.
To simplify it I have a main.h where I HAVE to define bool and some symbols to go along with it:
#ifndef main_h
#define main_h
#include <stdio.h>
#include "test.h"
typedef unsigned char bool;
#define TRUE 1
#define FALSE 0
#endif /* main_h */
Then the main.c HAS to use a type "num_seconds_t" and a function "test()", both of which have to be in a seperate file from main.
so I have my test.h:
#ifndef test_h
#define test_h
#include <stdio.h>
#include "main.h"
typedef int32_t num_seconds_t;
bool test(num_seconds_t var);
#endif /* test_h */
and my test.c:
#include "test.h"
bool test(num_seconds_t var){
num_seconds_t test = var;
return TRUE;
}
I don't think main.c would have any affect on this issue.
The error states unknown type "bool" in my test.h file, and I kind of understand why as when it hits the include for "test.h" within the main.h it starts going through that file before it has defined bool in main.h, then since main.h has "#ifndef main_h" when it hits "#include "main.h"" in the test.h it skips this and continues reading so bool never gets defined until after the test.h is done being read.
I am not sure if my understanding is correct, but what is the proper way of solving this. By simply moving the "#include "test.h"" to after the definition of bool it will compile, but in my big project I have many files that intertwine and coordinating the order of including these files would be very tough if not impossible.
Thanks
I'll present 3 solutions:
1) Your best option is to not #include test.h in main.h, since you don't need anything defined in test.h in main.h (you do need stuff from test.h in main.c, so test.h should be #includeed in main.c). This is good practice in general, as described in the comments (you don't want to #include something you don't need).
2) Your second best option is to move things from test.h and main.h to another file. In this case, you'd want to move your typedefs and #defines to another file like so:
typedef unsigned char bool;
#define TRUE 1
#define FALSE 0
typedef int32_t num_seconds_t;
and then include this file in main.h and test.h (or just in test.h because `main.h doesn't need these typedefs).
3) Your last and worst option is to carefully choose the order in which you include things. This is your worst option, since it gets very unwieldy with a large project, but I will show it nonetheless.
Leaving all your other files the same and doing:
// main.c
#include test.h
as the only include in main.c will solve your problem. When you try to compile this, only test.h will be #includeed in main.c. This will then include main.h, which has the typedefs you need for test.h. main.h won't include test.h again, since it has already been included. This is okay, because main.h doesn't actually need test.h.
You could also move your #include in main.h below your typedefs and include main.h in main.c. As I mentioned, however, option 3 is not a good option.
You should really do some combination of options 1 and 2 (in general, not just for this project).

C header file #ifndef #include error

I'm trying to figure out, how to use C headers with #ifndef and #include.
Lets say I have these two header files:
headerA.h:
#ifndef HEADERA_H
#define HEADERA_H
#include "headerB.h"
typedef int MyInt;
TFoo foo;
... some other structures from headerB.h ...
#endif
headerB.h
#ifndef HEADERB_H
#define HEADERB_H
#include "headerA.h"
typedef struct foo{
MyInt x;
} TFoo;
#endif
headerA.c
#include "headerA.h"
... some code ...
headerB.c
#include "headerB.h"
... some code ...
When compiling headerB.c, it says
In file included from headerB.h,
from headerB.c:
headerA.h: error: unknown type name ‘MyInt’
I think, it's becouse when headerB.h is compiling, it defines HEADERB_H and then, when headerA.h wants to include headerB.h, the #ifndef HEADERA_H is false = skips including.
What is the best practice here? I just read, that best practice is to do all #include directives in header files, but in this situation it looks like a problem.
EDIT: Ok, sorry for misleading you. This is just and example from bigger project with more files.
You have a circular dependency. Header file headerA.h depends on headerB.h which depends on headerA.h and so on and on.
You need to break that dependency, for example by not including headerB.h in headerA.h. It's not needed (nothing in headerA.h needs anything from headerB.h).
If you have to include headerB.h (as stated in your recent edit) then you first should reconsider how you use your header files, and what definition you place where. Perhaps move the definition of MyInt to headerB.h? Or have more header files, like one for type-aliases (like your MyInt which I personally see no use for), one for structures and one for variable declarations?
If that's not possible then you could try by changing the order of definitions and the include, like
#ifndef HEADERA_H
#define HEADERA_H
// Define type alias first, and other things needed by headerB.h
typedef int MyInt;
// Then include the header file needing the above definitions
#include "headerB.h"
TFoo foo;
... some other structures from headerB.h ...
#endif
Just drop the line
#include "headerB.h"
from file headerA.h

Why only define a macro if it's not already defined?

All across our C code base, I see every macro defined the following way:
#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS 0.2f
#endif
#ifndef BEEPTRIM_ROLL_RATE_DEGPS
#define BEEPTRIM_ROLL_RATE_DEGPS 0.2f
#endif
#ifndef FORCETRIMRELEASE_HOLD_TIME_MS
#define FORCETRIMRELEASE_HOLD_TIME_MS 1000.0f
#endif
#ifndef TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS 50.0f
#endif
What is the rationale of doing these define checks instead of just defining the macros?
#define BEEPTRIM_PITCH_RATE_DEGPS 0.2f
#define BEEPTRIM_ROLL_RATE_DEGPS 0.2f
#define FORCETRIMRELEASE_HOLD_TIME_MS 1000.0f
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS 50.0f
I can't find this practice explained anywhere on the web.
This allows you to override the macros when you're compiling:
gcc -DMACRONAME=value
The definitions in the header file are used as defaults.
As I said in the comment, imagine this situation:
foo.h
#define FOO 4
defs.h
#ifndef FOO
#define FOO 6
#endif
#ifndef BAR
#define BAR 4
#endif
bar.c
#include "foo.h"
#include "defs.h"
#include <stdio.h>
int main(void)
{
printf("%d%d", FOO, BAR);
return 0;
}
Will print 44.
However, if the conditional ifndef was not there, the result would be compilation warnings of MACRO redefinition and it will print 64.
$ gcc -o bar bar.c
In file included from bar.c:2:0:
defs.h:1:0: warning: "FOO" redefined [enabled by default]
#define FOO 6
^
In file included from bar.c:1:0:
foo.h:1:0: note: this is the location of the previous definition
#define FOO 4
^
I do not know the context but this can be used to give the user the availability to override the values set by those macro definitions. If the user explicitly defines a different value for any of those macros it will be used instead of the values used here.
For instance in g++ you can use the -D flag during compilation to pass a value to a macro.
This is done so that the user of the header file can override the definitions from his/her code or from compiler's -D flag.
Any C project resides on multiple source files. When working on a single source file the checks seem to (and actually) have no point, but when working on a large C project, it's a good practice to check for existing defines before defining a constant. The idea is simple: you need the constant in that specific source file, but it may have been already defined in another.
You could think about a framework/library that gives to the user a default preset that allow the user to compile and work on it.
Those defines are spreaded in different files and the final user is advised to include it's config.h file where he can config its values.
If the user forgot some define the system can continue to work because of the preset.
Using
#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS 0.2f
#endif
allows the user to define the value of the macro using the command line argument (in gcc/clang/VS) -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f.
There is another important reason. It is an error to re-define a preprocessor macro differently. See this answer to another SO question. Without the #ifndef check, the compiler should produce an error if -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f is used as a command line argument in the compiler invocation.

mutual inclusion of header files with global variables

I have a number of modules in a C program for a microcontroller not running any OS. Each module has its own type definitions, enumerations, and data structre definitions to represent the module's status and I think it would be neat to define them in the module's associated header file.
Then, I have a global variable defined in global_var.c to "remember" the current status of the whole system. Since the modules' data structures are being referred to in the global variable's definition, all the module headers are being included in global_var.h.
However, these modules will also need to access the global variable thus they will need to include global_var.h as well.
How can I avoid mutual inclusion of the header files if I really want to keep my global variable?
Many thanks!
global_var.h
#ifndef GLOBAL_VAR_H
#define GLOBAL_VAR_H
#include "module.h"
typedef struct GLOBAL_STRUCTURE {
module_structure m;
} global_structure;
#endif
global_var.c
#include "global_var.h"
global_structure gs;
module.h
#ifndef MODULE_H
#define MODULE_H
typedef struct MODULE_STRUCTURE {
int a;
} module_structure;
void module_function(void);
#endif
module.c
#include "global_var.h"
extern global_structure gs;
void module_function(void) {
gs.m.a=0;
}
I think the C language is supposed to share a global defined twice. but it depends on the compiler (well linker) as to whether your toolchain actually does that I have had some that do and some that dont. The safest route is to only declare the variable once and everywhere else explicitly declare it as extern. You will often see this done like this:
common.h
#ifundef HELLO
#define HELLO
#endif
HELLO unsigned int myglobx;
one.c
#include "common.h"
two.c
#include "common.h"
three.c
#define HELLO extern
#include "common.h"
Try this:
In Module.c
#define XYZ
then in Module.h
#define MODULETYPE
#ifdef XYZ
MODULETYPE
#else
MODULETYPE extern
#endif
MODULETYPE int var1,var2;
Do this for every module and include your header wherever you want.

How to include a specific header file without having a conflict

My Files are
main.c
#include"A.h"
#include"B.h"
A.c
#include"A.h"
B.c
#include"B.h"
I have a file with a couple of structures that I have defined that I am supposed to use in all the files i.e A.c , B.c, main.c and even the header files for A and B.
Hence I have
A.h and B.h both have
#include"struct.h"
Now, I see that in my main.c
I will have multiple declaration for both the structures, how do I get rid of this problem. What shall I change in my structure?
Thanks
Use include guards.
aheader.h:
#ifndef AHEADER_H
#define AHEADER_H
// ... rest of header here
#endif
bheader.h:
#ifndef BHEADER_H
#define BHEADER_H
// ... rest of header here
#endif
You can use a guard as such,
#ifndef MY_STRUCT
#define MY_STRUCT
#include "struct.h"
#endif
If you want to selectively take care of which parts should not be duplicated
Wrap the header files in include guards., like this:
#ifndef MYHEADER_H
#define MYHEADER_H
// your definitions
#endif
Each header file should have its own guard with an unique name. The above preprocessor directives translated to english say something like: "If MYHEADER_H is not defined, then define it and paste the contents until #endif directive." This guarantees that a single header is included only once inside a single translation unit.
Simply use so called header guard to be sure of including "struct.h" only once:
// struct.h
#ifndef STRUCT_H
#define STRUCT_H
struct ...{
}
#endif

Resources