'Why does this .c file #include itself?
Why does this .c file #include itself?
vsimple.c
#define USIZE 8
#include "vsimple.c"
#undef USIZE
#define USIZE 16
#include "vsimple.c"
#undef USIZE
#define USIZE 32
#include "vsimple.c"
#undef USIZE
#define USIZE 64
#include "vsimple.c"
#undef USIZE
Solution 1:[1]
The accepted answer by @chqrlie 100% explains what is happening. This is just a complementary commentary.
If using C++ we could define two template functions to provide all the implementations of vsenc8, vsenc16, vsenc32, vsenc64 and vsdec8, vsdec16, vsdec32, vsdec64. In contrast, however, C is a very simple language and does not support templates. A common trick to have the same power (in uglier packaging) is to use the dumb macro facility of the language and let the C preprocessor do the equivalent job for us. Most C programmers of some experience will encounter and use this kind of construct repeatedly during their careers.
What makes this particular example a bit tedious to understand is that the implementation file is unconventionally parsed 5 times to first have some preparatory definitions and then the four variants of the two functions. The first pass (inside #ifndef USIZE preprocessor block) will have the needed macros and non-variant stuff defined and will recursively #include itself four times with different USIZE values (8, 16, 32, 64) as template values. When recursively included, the corresponding #else preprocessor block is parsed with the result of two functions generated according to the value of USIZE macro constant used for the pass.
More conventional, conceptually clearer, and instantly understandable way would be to include the template functions from a different files, say vsimple.impl:
#define USIZE 8
/* Generate vsenc8(), vsdec8()... */
#include "vsimple.impl"
#undef USIZE
#define USIZE 16
/* Generate vsenc16(), vsdec16()... */
#include "vsimple.impl"
#undef USIZE
#define USIZE 32
/* Generate vsenc32(), vsdec32()... */
#include "vsimple.impl"
#undef USIZE
#define USIZE 64
/* Generate vsenc64(), vsdec64()... */
#include "vsimple.impl"
The including file vsimple.c and the included file vsimple.impl could then also be organized to be much clearer in what they define and when. Most C programmers would recognize the implementational pattern and immediately know what is happening.
Recursively and repeatedly including itself this way invokes a feel of hocus-pocery which would attract applauds for an obfuscated C competition entry but not for mission critical production code.
Solution 2:[2]
It is recursion. Recursion is useful here because C preprocessing doesn't have looping. Moreover, it's desirable to perpetrate a trick using one file rather than proliferating multiple files.
Suppose you were required to write a function which interpolates the integers from 1 to 5 into a template string, and prints that on standard output. Suppose you were required to write exactly one function and were prohibited from loops, or copy-pasted printf statements. You might do this:
void template_print(const char *fmt, int n)
{
if (n == 0) {
template_print(fmt, 1);
template_print(fmt, 2);
template_print(fmt, 3);
template_print(fmt, 4);
template_print(fmt, 5);
} else {
/* imagine there are 30 lines of statements here we don't want
to repeat five times. */
printf(fmt, n);
}
}
The top-level call to this is then template_print("whatever %d\n", 0) distinguished by the zero argument of the n parameter.
The top-level call with 0 is like the initial processing of vsimple.c without USIZE being defined.
The requirement for one function is analogous to being required to produce a single, self-contained .c file rather than an "interface" file which #includes an implementation.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Kaz |
