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

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.

Related

How come the preprocessor directives in my header are not seeing the macro I put above the #include in source? (C code)

I am attempting some conditional compilation for unit testing static functions in C. (roughly following the method outlined in this answer https://stackoverflow.com/a/593437/8347016)
I have it set up like so:
check_blah.c
#define UNIT_TEST 1
#include "blah.h"
#include "testframework.h"
...
blah.h
#if UNIT_TEST
#define u_static
#else
#define u_static static
#endif
...
#if UNIT_TEST
void foo(/* some parameters */)
#endif
blah.c
#include "blah.h"
...
u_static void foo(/*some parameters */) {
/* some definition */
}
...
And just to cover my bases, here is how the files are compiled in make
check_blah: check_blah.c blah.o testframework.o
gcc check_blah.c blah.o testframework.o -o check_blah
blah.o: blah.c blah.h
gcc -c blah.c -o blah.h
testframework.o: /* similar to above */
If I compile check_blah without it having any references to foo, and then run gdb info functions, I see that foo is considered static even though UNIT_TEST is defined. Even more confusing, the compiler somehow does recognize UNIT_TEST as defined. In an experiment I defined a macro, SPEEP to be 10 if UNIT_TEST was defined and 100 otherwise. Then in check_blah.c I set some int to SPEEP and then printed it. It would print 10! So the line #define ustatic MUST be being hit as well, but somehow it isn't since foo remains static.
If I take the line #define UNIT_TEST 1 and move it to the top of blah.h, everything seems to work (i.e, info functions claims foo is not static).
So does anyone know the reason for this awkward (and inconsistent looking) behavior with preprocessor macros and directives?

What does a #define directive without an argument do?

On Apple's opensource website, the entry for stdarg.h contains the following:
#ifndef _STDARG_H
#ifndef _ANSI_STDARG_H_
#ifndef __need___va_list
#define _STDARG_H
#define _ANSI_STDARG_H_
#endif /* not __need___va_list */
#undef __need___va_list
What do the #define statements do if there's nothing following their first argument?
There are sort of three possible "values" for an identifier in the preprocessor:
Undefined: we don't know about this name.
Defined, but empty: we know about this name, but it has no value.
Defined, with value: we know about this name, and it has a value.
The second, defined but empty, is often used for conditional compilation, where the test is simply for the definedness, but not the value, of an identifier:
#ifdef __cplusplus
// here we know we are C++, and we do not care about which version
#endif
#if __cplusplus >= 199711L
// here we know we have a specific version or later
#endif
#ifndef __cplusplus // or #if !defined(__cplusplus)
// here we know we are not C++
#endif
That's an example with a name that if it is defined will have a value. But there are others, like NDEBUG, which are usually defined with no value at all (-DNDEBUG on the compiler command line, usually).
They define a macro which expands to nothing. It's not very useful if you intended it to be used as a macro, but it's very useful when combined with #ifdef and friends—you can, for example, use it to create an include guard, so when you #include a file multiple times, the guarded contents are included only once.
You define something like:
#define _ANSI_STDARG_H_
so that, later you can check for:
#ifdef _ANSI_STDARG_H_

Using C, one code, multiple headers if/else?

I have one piece of code that I can use for the same function on different sets of data which are defined in different header files . These header files may have the same variable defined differently.
I can pass a parameter to the code when I call it to specify which dataset I want to perform the function on.
What I would like to do is pass this parameter to the code where if the parameter equals X then I use headerX, or if parameter equals Y I use headerY.
It is my understanding that header files must be included before MAIN. Is it possible to include the header file after MAIN so that I can write an if/else statement to determine which header file I am calling?
If I can't do that then please help me figure this out.
You could use #ifdef - blocks to determine which data set you'd want to use before compiling. But if you wanted a different data set, you would need to change (recompile) the executable by changing that define.
Otherwise you would need to compile in C++ as straight C does not support overloaded functions.
Simply put, you just can't. You may be able to include headers before hand based on a condition. Just use #if-def blocks at the top of the file.
But you can't include it like if else:
This is WRONG
if(x == 1)
#include "header1.h"
else
#include "header2.h"
But you can do this at the top of the file:
#if SYSTEM_1
#include "system_1.h"
#elif SYSTEM_2
#include "system_2.h"
#elif SYSTEM_3
#include "system_3.h"
#endif
Or you could just use C++ which does support overloaded functions.
You can do simple metaprogramming by using the macro preprocessing phase. Create a "interface_myFunc.h" with something like
#define FUNCNAME(T) myFunc_ ## T
void FUNCNAME(theType)(theType t);
Create a "implement_myFunc.h" file with something like
void FUNCNAME(theType)(theType t) {
// do something with t
}
and then include this file in another file "myFunc.h"
#define theType toto
#include "interface_myFunc.h"
#undef theType toto
#define theType tutu
#include "interface_myFunc.h"
#undef theType tutu
and similar for the definitions, "myFunc.c"
#define theType toto
#include "implement_myFunc.h"
#undef theType toto
#define theType tutu
#include "implement_myFunc.h"
#undef theType tutu
Modern C, C11, also has ways to create a common interface for all these functions that you create by so-called type generic macros:
#define myFunc(X) \
_Generic((X), \
toto: FUNCNAME(toto), \
tutu: FUNCNAME(tutu) \
)(X)

Most elegant way to share a C array

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.

redefining a constant in C

If I have a constant defined as such in a header file:
#define MY_CONSTANT 1
And I include a library to the whole project which includes a different definition for the same constant:
#define MY_CONSTANT 0
I naturally get conflicts while compiling. Supposing that I cannot alter my project code and that I can only change my library code, what can I do to make MY_CONSTANT as defined by my lib?
EDIT:
just to clarify, my goal is to update a constant in my code through a library. Because I'm writing a library to simulate hardware functions, I have to go by the rule that the software itself must be untouched. There is a loop of sort in the main file that uses the constant. I need to change this constant, but without actually altering it in the main file.
You can undefine the other definition
#ifdef MY_CONSTANT
#undef MY_CONSTANT
#endif
#define MYCONSTANT 0
Also, you should remove the =, and the ;
P.S. as mentioned, it will not change the code that already compiled.
You can #undef MY_CONSTANT and redefine to the value you want, but that's just asking for trouble. See if you can modify the design entirely so that MY_CONSTANTs don't clash.
Undef, redef, and then redef it back
#ifdef MY_CONSTANT
#undef MY_CONSTANT
#endif
#define MY_CONSTANT 0
/* code here */
#undef MY_CONSTANT /* not needed if you don't need the library's definition*/
#include "library.h" /* file that originally defined it
might not work if include guards prevent it
in that case #undef LIBRARY_H
although that causes more trouble :( */

Resources