Including one C source file in another?

192,416

Solution 1

Used properly, this can be a useful technique.

Say you have a complex, performance critical subsystem with a fairly small public interface and a lot of non-reusable implementation code. The code runs to several thousand lines, a hundred or so private functions and quite a bit of private data. If you work with non-trivial embedded systems, you probably deal with this situation frequently enough.

Your solution will probably be layered, modular and decoupled and these aspects can be usefully represented and reinforced by coding different parts of the subsystem in different files.

With C, you can lose a lot by doing this. Almost all toolchains provide decent optimisation for a single compilation unit, but are very pessimistic about anything declared extern.

If you put everything into one C source module, you get -

  • Performance & code size improvements - function calls will be inlined in many cases. Even without inlining, the compiler has opportunities to produce more efficient code.

  • Link level data & function hiding.

  • Avoidance of namespace pollution and its corollary - you can use less unwieldy names.

  • Faster compilation & linkage.

But you also get an unholy mess when it comes to editing this file and you lose the implied modularity. This can be overcome by splitting the source into several files and including these to produce a single compilation unit.

You need to impose some conventions to manage this properly though. These will depend on your toolchain to some extent, but some general pointers are -

  • Put the public interface in a separate header file - you should be doing this anyway.

  • Have one main .c file that includes all the subsidiary .c files. This could also include the code for the public interface.

  • Use compiler guards to ensure that private headers and source modules are not included by external compilation units.

  • All private data & functions should be declared static.

  • Maintain the conceptual distinction between .c and .h files. This leverages existing conventions. The difference is that you will have a lot of static declarations in your headers.

  • If your toolchain doesn't impose any reason not to, name the private implementation files as .c and .h. If you use include guards, these will produce no code and introduce no new names (you may end up with some empty segments during linkage). The huge advantage is that other tools (e.g. IDEs) will treat these files appropriately.

Solution 2

is it ok? yes, it will compile

is it recommended? no - .c files compile to .obj files, which are linked together after compilation (by the linker) into the executable (or library), so there is no need to include one .c file in another. What you probably want to do instead is to make a .h file that lists the functions/variables available in the other .c file, and include the .h file

Solution 3

No.

Depending on your build environment (you don't specify), you may find that it works in exactly the way that you want.

However, there are many environments (both IDEs and a lot of hand crafted Makefiles) that expect to compile *.c - if that happens you will probably end up with linker errors due to duplicate symbols.

As a rule this practice should be avoided.

If you absolutely must #include source (and generally it should be avoided), use a different file suffix for the file.

Solution 4

I thought I'd share a situation where my team decided to include .c files. Our archicture largely consists of modules that are decoupled through a message system. These message handlers are public, and call many local static worker functions to do their work. The problem came about when trying to get coverage for our unit test cases, as the only way to exercise this private implementation code was indirectly through the public message interface. With some worker functions knee-deep in the stack, this turned out to be a nightmare to achieve proper coverage.

Including the .c files gave us a way to reach the cog in the machine we were interesting in testing.

Solution 5

You can use the gcc compiler in linux to link two c file in one output. Suppose you have two c files one is 'main.c' and another is 'support.c'. So the command to link these two is

gcc main.c support.c -o main.out

By this two files will be linked to a single output main.out To run the output the command will be

./main.out

If you are using function in main.c which is declared in support.c file then you should declare it in main also using extern storage class.

Share:
192,416
S.S. Anne
Author by

S.S. Anne

Updated on September 04, 2020

Comments

  • S.S. Anne
    S.S. Anne over 3 years

    Is it OK (or even recommended/good practice) to #include a .c file in another .c file?

  • Nick Meyer
    Nick Meyer almost 15 years
    Also worth noting that even if it compiles, it might not link if the #included .c file is also compiled and the two object files are linked together -- you could end up with multiply defined symbols.
  • u0b34a0f6ae
    u0b34a0f6ae almost 14 years
    +1 this is still the reality, while better compilers will make this method obsolete with time. GCC 4.5 with link-time optimization is a big step on the way.
  • Joey Adams
    Joey Adams almost 13 years
    I've seen so many programs do this, and it gets on my nerves when I'm trying to reuse their code. Thanks for explaining why they do it, and suggesting the use of a guard (which often isn't done).
  • mahesh
    mahesh about 7 years
    In embedded development for C51, use of extern & multiple C files has caused nothing but headaches. I'm switching over to having one C file include all others to get back my time.
  • Twonky
    Twonky about 6 years
    For the records: GCC supports optimization across different translation units, see this SO thread and GCC manual section on link time optimization.
  • stdout
    stdout about 5 years
    A small question. I've a header file declaring a struct + method and also the corresponding .c file to define them. If that method takes the struct as a parameter , how would I avoid including the .c file in another .c file where the main method is defined?
  • mtraceur
    mtraceur about 3 years
    Also for the record: link-time optimization is inherently harder unless you can somehow keep all the information available to the compiler from the C source files associated with the code in the object files being linked (which is essentially what the above link describes GCC doing). For other developers to benefit from your distributed object files, LTO requires larger object files to achieve the same optimizations. Depending on how LTO is Implemented, it probably can't achieve 100% of the optimizations that optimizing within a single translation unit can. LTO can also make builds slower.
  • mtraceur
    mtraceur about 3 years
    None of my previous comment is to say that LTO is bad, just that LTO is not currently, and perhaps never will be, just as good at providing the benefits described in this answer from including multiple C files in one translation unit.