Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

169
Views
Why does this .c file #include itself?

Why does this .c file #include itself?

  • https://github.com/powturbo/TurboPFor-Integer-Compression

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
over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

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.

over 4 years ago · Santiago Trujillo Report

0

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.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!