Why should #ifdef be avoided in .c files?
(Somewhat off the asked question)
I saw a tip once suggesting the use of #if(n)def/#endif
blocks for use in debugging/isolating code instead of commenting.
It was suggested to help avoid situations in which the section to be commented already had documentation comments and a solution like the following would have to be implemented:
/* <-- begin debug cmnt if (condition) /* comment */
/* <-- restart debug cmnt {
....
}
*/ <-- end debug cmnt
Instead, this would be:
#ifdef IS_DEBUGGED_SECTION_X
if (condition) /* comment */
{
....
}
#endif
Seemed like a neat idea to me. Wish I could remember the source so I could link it :(
Because then when you do search results you don't know if the code is in or out without reading it.
Because they should be used for OS/Platform dependencies, and therefore that kind of code should be in files like io_win.c or io_macos.c
Hard to maintain. Better use interfaces to abstract platform specific code than abusing conditional compilation by scattering #ifdef
s all over your implementation.
E.g.
void foo() {
#ifdef WIN32
// do Windows stuff
#else
// do Posix stuff
#endif
// do general stuff
}
Is not nice. Instead have files foo_w32.c
and foo_psx.c
with
foo_w32.c:
void foo() {
// windows implementation
}
foo_psx.c:
void foo() {
// posix implementation
}
foo.h:
void foo(); // common interface
Then have 2 makefiles1: Makefile.win
, Makefile.psx
, with each compiling the appropriate .c
file and linking against the right object.
Minor amendment:
If foo()
's implementation depends on some code that appears in all platforms, E.g. common_stuff()
2, simply call that in your foo()
implementations.
E.g.
common.h:
void common_stuff(); // May be implemented in common.c, or maybe has multiple
// implementations in common_{A, B, ...} for platforms
// { A, B, ... }. Irrelevant.
foo_{w32, psx}.c:
void foo() { // Win32/Posix implementation
// Stuff
...
if (bar) {
common_stuff();
}
}
While you may be repeating a function call to common_stuff()
, you can't parameterize your definition of foo()
per platform unless it follows a very specific pattern. Generally, platform differences require completely different implementations and don't follow such patterns.
- Makefiles are used here illustratively. Your build system may not use
make
at all, such as if you use Visual Studio, CMake, Scons, etc. - Even if
common_stuff()
actually has multiple implementations, varying per platform.