When should a .c file not have an associated .h file?
Most of the time in C programming it seems that there will be one header file (.h
) per code file (.c
), for the function prototypes at 开发者_如何学Goleast.
When would it be appropriate to not have a header file for a code file?
There's a few use cases for this. The most obvious is that your main program rarely needs a header file.
The second is where you don't have one header for each C file. I've put together libraries before (let's say a BTree library for the purposes of this answer) where each individual function is in its own source file but there's a library-wide header file, something like:
btree.h
btree_priv.h
btreeInit.c
btreeDestroy.c
btreeConfig.c
and so on. The private header file is for stuff that need to be shared between the code but is not to be published in the API.
most obviously when the .c
is fully self contained and does not need to have prototypes or extern's for other .c
files. this basically is only for very small programs, or those that export via a def file to plugin in to a predefined interface.
I have seen massive code bases where a single .h
file defines the interface to some component, and several .c
files implement it. The implementation was divided into several files purely for maintainability reasons, and was attempted at some logical bounds.
One could argue that such a logical bound could be applied to divide the component into sub-components and consequently have several header files, but design decisions are rarely a black&white affair, and sometimes this approach does make sense.
When the .c file contains data that does not need to be used by any code.
Admittedly this is rare - but it can happen. For example I have done this in embedded devices, to populate the video frame buffer with boot graphics.
If you divide your program into a number of modules, there will usually be a "main" module, which contains the main() function and perhaps some other stuff. If this module doesn't have anything that is supposed to be called or used by another module, you don't need to export an interface in a .h file.
I think expecting a 1-to-1 mapping between .c and .h files is a bad starting assumption. Throw that out and start fresh. :D
Looking at your question differently, you might ask "When is it appropriate to create a header file?"
I'll suggest the following, where the term "code module" is a group (generally a directory) of one or more related .c files:
- Create a header for public interfaces/definitions that must be available to other code modules.
- Create a header for private interfaces/definitions that must be shared within a code module but not shared with other code modules.
Those are the only header files you should need. If neither of those are required then you don't need a header.
Some coders like to artificially separate prototypes/macros/typedefs/etc into a .h separate from the globals/functions in their .c. I recommend against this approach and suggest having all related functionality in one file. Then move to headers as-needed those things that are absolutely necessary to prevent 'extern's in other .c files.
In case, when you wouldn't need the declarations from the .h
file, but that is effectively never.
Oftentimes, I'll create a header file for 'main' even if I'm not expecting other code to have to access it, since frequently either (1) a debug build will end up requiring something outside the main module to access something within it, or (2) the main module will end up having to be split due to (embedded system) compiler limitations. The pattern of having every .c file include its own .h file is sufficiently strong that I'll often create nearly-empty .h files even for .c files that define things which aren't referenced in code (like interrupt-jump tables, etc.).
Naming conventions get a little trickier when a file includes multiple program-generated files, or includes files that need to be compiled more than once (e.g. one of my projects has two motors, whose code is identical except that they use different I/O ports and different variables; my motor.c file contains:
#define LOCK L0 #include "motor.i" #undef LOCK #define LOCK L1 #include "motor.i" #under LOCK
Note that on this particular embedded compiler, the -> operator is very inefficient, so a statement like:
L0.speed++;
will compile to one instructions, while a statement like:
L0->speed++;
will translate into five instructions if 'speed' is the first item in the structure, or seven if it occupies any other position. It is thus far more speed-efficient, and somewhat more space-efficient, to duplicate code with constant resolvable addresses than to have one routine handle both motors.
If there's one extra file associated with a .c file, and it contains real code, I'll name it ".i". Not sure what to do if there's more than one, though.
精彩评论