Function prefix comments in C files

Sep 27, 2005 53 Replies

Hi



It's common practice to prefix a function definition in a .C file with comments in a standard format that describe the function, its parameters and inputs/outputs.



Is it common practice to duplicate this information as a prefix to the function prototype in a header .h file. or to not have it in the .c file at all and only in the header file?



TIA


I'd say, it depends. If I'm writing code for my own products/projects, I place a comment in the C file above each function and not in the header file. To keep it at two places is a source for mistakes because sooner or later, you forget to update one of them.

When the header file is to be delivered as an interface with an object file, I would place it in the header file.

Meindert

Right.

Have you ever done this or do you have any examples of this being done?

As an aside, it seems a sensible policy when using markup for a documentation generator (such as Doxygen[1]); because this documentation is meant to show the 'what' and not the 'how' normally covered by internal comments. Obviously, as Meindert points out, it would be silly to have this in both the header and the source, and since the header would normally be distributed as the API, it's convenient for the documentation ('what') to be integral to it.

Absent a document generator, either way could work, but in my own projects I would tend to use the .c (definition) and do all commenting (internal and external) there, leaving the .h and prototypes free of comments.

Just my .01c. [1]

formatting link

file,

No. It's just how I would do it.

Meindert

First, I put public function definitions only in the header file, and private function definitions (all defined static to enforce limited scope) only in the .c file.

Second, I try to ensure the public function definition's usage is obvious.

Third, I consider that the header file, being public, *is* the interface - therefore if I'm being particularly assiduous, I'll include commentary in the header file to document usage. (However I don't duplicate the commentary in the .c file - that's often concerned with "how", rather than "what".)

HTH,

Steve

formatting link

I assume you mean declarations, not definitions. Function prototypes are not definitions.

So does this mean that for "exported" functions (functions with external linkage), the function prefix description is with the prototype and for non-exported functions the description is with the function definition (implementation) .

How? In my code, identifier names are made as meaningful and descriptive as possible as concisely as possible, regardless of where they appear.

I find that the description that prefixes the function needs to be with the function definition in the .c file because it needs to be referred to when examining the function implementation. e.g. it describes the inputs and pre-conditions - things you need to know when checking the implementation.

For C++ code, I don't recall ever seeing a class definition that included "function description details" within the class definition (which is an interface).

Thanks for the reply.

darkknight

You're right. (I plead insanity due to heavy-duty painkillers.)

Kinda. I tend not to muddy up the function prototypes as such - I tend to include a "howto" in the .h file that explains usage instead.

Yeah, that's what I do. But also good decomposition helps.

Absolutely. See my earlier reply re "how" (the implementation) vs "what" (the interface).

Ah. I was talking about C rather than C++, which I prefer not to use (but that's another story that we've discussed rather a lot here ;)).

Steve

formatting link

It doesn't happen as often as it should.

That said, if a UML tool is being used to generate the class declaration (as is increasingly happening with C++), that is the place to have the documentation. Then it matters less if it doesn't get through to the .h file.

-- Peter Bushell

formatting link

I have seen this done in a C++ package delivered to us as a linkable library we licensed. It included the library and a set of commented .h files that defined all of the class information.

Scott

On Tue, 27 Sep 2005 18:49:19 +1200, darkknight wrote in comp.arch.embedded:

I work for a large organization where as 10 or so programmers might well be working on a large, complex embedded program. We adopted our current rules about 3 years ago.

First, the application is partitioned into tasks (when there are multi-tasking operating systems) or modules. Each task or module is assigned to a programmer. Each task or module gets its own directory in the top-level source code directory, which contains nothing but directories.

There is a single common include directory where each task/module provides two headers. One header includes the prototypes for all of the functions that are available to be called from other tasks/modules. The other header, which is not particularly relevant here, contains typedefs and possible some macros that other tasks/modules might need to use in calling those exported API functions.

If I am going to call a function in the XYZ task, written by somebody else, there is no way I want or need or should have to look in the xyz directory at the source code to find information about how to call a function xyz exports. So the Doxygen function header block goes in the header file that prototypes the function:

/***************************************************************************/ /** PS_GetValue - This function reads a configuration value owned by * the Persistent Storage subsystem. * * \param token - A token that specifies which value is to be read * (for possible values see description of enum ps_value_token_t). * \param dest - A pointer to a location where the requested * value is to stored * \return error_code_t, OK or BAD_PARAMETER

***************************************************************************/ error_code_t PS_GetValue(ps_value_token_t token, uint32_t *dest);

Since we don't want the information duplicated, there is a much smaller comment block with the definition of the function in a source code file, its main purpose is to indicate the header that includes the prototype and full comment block:

/***************************************************************************/ /** PS_GetValue - see ps_api_calls.h for details

***************************************************************************/ error_code_t PS_GetValue(ps_value_token_t token, uint32_t *dest) { /* body */ }

By the way, the 'PS_' prefix in this example indicates that the function is part of the PS module that manages the persistent storage (SPI EEPROM) in this particular application.

An individual task/module often has several different source code files itself, and needs to make function calls between them. So each has one or more internal headers, and the same thing applies here, the full comment is in the header with the prototype, the abbreviated header in the source file mainly to identify which header file contains the prototype and full comment.

Finally, any static functions within a source file are prototyped with the full comment block before any code. Again, the function definition later in the body has the abbreviated block which merely says "see prototype in this file for details".

Of all the various systems I've used at different companies and on different teams over the years, I think this one scales best to C projects with more than one or two programmers involved.

I may need to look at your source code for a code inspection, or to work on it while you're on vacation or have moved on to another project. I should not have to look at your source code to see how to call your function, and what the parameters and return values are.

The header file should be the interface to the function to both the compiler and other programmers.

Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html comp.lang.c++ http://www.parashift.com/c++-faq-lite/alt.comp.lang.learn.c-c++ http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

What about this suggestion:

One is not restricted to the use of .h or .c for files extensions. Suppose you have these files, module.c module.h, module.ch, module.hh.

module.h contains the declaration of functions and module.c the implementation as usual.

module.hh contains comments related only to the public interface of module, for instance comments about exported functions and parameters.

module.ch includes module.hh and adds comments related to private implementation. module.h includes module.hh module.c includes module.ch

I also consider the header file as the interface definition. It gets full documentation on use of the public functions. It does not have any private functions or types / constants used only within the definition. If there is a confusion about the operation of a function, it is a strong indication that it wasn't documented properly in the header file.

As as aid to myself, I copy the header comments and declaration into the code file. If I change it one place, I am careful about updating it in the other place. Strictly speaking, this is a violation of the single source definition principle (also called DRY -- Don't Repeat Yourself), but worthwhile for me. It would, of course, be possible to automate copying from one place to the other.

Thad

=== SNIP ===

Yes, I am late to the party, but if there is anyone who is still sober...

I have come across this 2-header model before; that is, one header file with only function prototypes and another header file containing the 'magic goodies' required to utilize those prototyped functions.

I have been searching for (not in a Google way, but rather by asking organizations "why is this in your coding standards?" way), and not yet found, a justification for the 2-header model. Invariably, I find that files including the prototype header end up including the 'other' header. I am eager to learn why the 2-header model is used. Can anybody enlighten me?

-- Dan Henry

Heh, sounds like a compromise between those that insist that design documentation be included in the source code, and those (like myself) who *detest* code polluted by more than a spattering of comments.

Ever tried maintaining code that consists of twenty-odd 5-line routines interleaved with 2 pages of comments between each function? Or scrolling thru 5 pages of header comments to find a #define value or function prototype? It gets annoying *very* quickly - even with a scroll-wheel!

IMHO Code comments should be restricted to brief 'and this block does this...'-style comments and tricky/subtle/unusual implementation details

- the rest belongs in the (completely separate) design document.

Regards, Mark

Years ago when using an Intel compiler for an 80C196KC, I was taught this 'trick' by the Intel support guys. I'm sure that compilers have significantly improved since then and that this method is probably not NEEDed any longer--but I continue to use it for several reasons. The original reason driving this method was that it gave both compiler and linker more visibility into the overall project and thus was able to better optimize and figure out which variables could be overlaid and which couldn't. This became a real issue when you started running out of available RAM on the part.

Here's the synopsis:

all function prototype are in one file: prototype.h all macros, #defines are in one file: defines.h

all globals are in one file: globals.h inside of globals.h at the top:

" #ifdef GENERATING_GLOBALS #define Global #else #define Global extern #endif " All variable in the global.h file are then declared like:

Global char buffer[SIZE]

Then in your main.c file, and ONLY in main.c:

#define GENERATING_GLOBALS 1

All files then have this:

#include defines.h #include prototype.h #include globals.h

As said earlier, this method is probably not required any longer for overlay/optimization purposes, but I continue to use on small one or two person projects because:

1) want to know if a variable is global? look in globals.h 2) want to know what a function prototype is? look in prototype.h 3) want to know what EISR is defined to be? look in defines.h

It's a super convenient way to know what things are without searching a bunch of h files to find it. I further added to Intel's suggestion by creating a types.h file in which all typedefs, union, and struct definitions reside.

Downsides: any change to any of these three files will cause re-compile/rebuild of ALL project files. does not work well for large or multi-person projects

Hope this helps answer your question....

Bo

You've lost me. It seems that you are creating a situation where you

*must* search a bunch of files to find it. If all the above were in one file, there's only one place to look. In fact, most things would be identifiable just by grepping the file for the name.
Al Balmer Balmer Consulting removebalmerconsultingthis@att.net

I often heavily document the function prototypes in the header file. The intent is that a user need look only in one place for all the information needed to use the functions prototyped.

Most editors I use will find such very quickly without using a scroll wheel, or even a mouse.

Al Balmer Balmer Consulting removebalmerconsultingthis@att.net

You could do that, of course. For me, that would separate the comments and relevant code too much (.c and .ch). The way I use interface .h files, all the interface details are in that one file, with the function comments just above the associated declaration, thus keeping the human- and machine-readable interface details together. It helps me keep them in sync. If you are going to have external documentation, you might as well make it a text or word processor file.

I prefer this style:

/*******************************/ Find the configuration value from the Persistent Storage subsystem identified by ``token'' and store it at ``dest''. Return OK or BAD_PARAMETER , whatever applies. /*******************************/

I think the function prototype can be taken for granted. It cannot reasonably be duplicated in the description, so I don't try.

What I try to tell is, I hate descriptions where the action is separated from the objects. It is verbose and if taken litterally, not really watertight. For example, you could get away with always returning ``OK'' and claim that it is within spec.

(OTOH, if there is a general remark about error codes on top of the c-file, you should leave it out of the function description. That would be okay. )

--

Albert van der Horst, UTRECHT,THE NETHERLANDS Economic growth -- like all pyramid schemes -- ultimately falters. albert@spenarnc.xs4all.nl http://home.hccnet.nl/a.w.m.van.der.horst

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required