embedded software boot camp

Effective C Tip #4 – Prototyping static functions

Saturday, July 4th, 2009 by Nigel Jones

This is the fourth in a series of tips on writing effective C.

I have previously talked about the benefits of static functions. Today I’m addressing where to place static functions in a module. This posting is motivated by the fact that I’ve recently spent a considerable amount of time wading through code that locates its static functions at the top of the file. That is the code looks like this:

static void fna(void){...}

static void fnb(uint16_t a){...}

...

static uint16_t fnc(void){...}

void fn_public(void)
{
 uint16_t t;

 fna();
 t = fnc();
 fnb(t);
 ...
}

In this approach (which unfortunately seems to be the more common), all of the static functions are defined at the top of the module, and the public functions appear at the bottom. I’ve always strongly disliked this approach because it forces someone that is browsing the code to wade through all the minutiae of the implementation before they get to the big picture public functions. This can be very tedious in a file with a large number of static functions. The problem is compounded by the fact that it’s very difficult to search for a non static function. Yes I’m sure I could put together a regular expression search to do it – but it requires what I consider to be unnecessary work.

A far better approach is as follows. Prototype (declare) all the static functions at the top of the module. Then follow the prototypes with the public functions (thus making them very easy to locate) and then place the static functions out of the way at the end of the file. If I do this, my code example now looks like this:

static void fna(void);
static void fnb(uint16_t a);
static uint16_t fnc(void);

void fn_public(void)
{
  uint16_t t;

 fna();
 t = fnc();
 fnb(t);
 ...
}

static void fna(void){...}

static void fnb(uint16_t a){...}

...

static uint16_t fnc(void){...}

If you subscribe to the belief that we only write source code so that someone else can read it then this simple change to your coding style can have immense benefits to the person that has to maintain your code (including a future version of yourself).

Update: There’s a very interesting discussion in the comments section – I recommend taking a look.
Next Tip
Previous Tip
Home

Tags:

8 Responses to “Effective C Tip #4 – Prototyping static functions”

  1. steve says:

    Agreed. Also, Lint complains if any function (static or otherwise) doesn't have a prototype in scope.

  2. Skinner says:

    Strongly agree, too.I tend to use a template with a dedicated section for private function declarations (and also private variable declarations).

  3. Anonymous says:

    Strongly disagree.>this approach […] forces someone that is browsing the code to wade through all the minutiae of the implementation before they get to the big picture public functions.Not so; you are not constrained to read source code from top to bottom of the file.>it's very difficult to search for a non static function.No it's not. They are all at the bottom of the file. Electronically search by name if you need to (all the names should be in the .h file).>follow the prototypes with the public functions (thus making them very easy to locate)They are just as easy to locate when they are all grouped at the end of the file.Having prototypes for static functions just gives you lots more lines of code to maintain. When you alter the signature of a static function, and hence are making a change local to the one .c file, you will need to make two identical changes if you have a prototype for it at the top of the file, but only one change if there are no static prototypes.As I understand it, the only danger from not having static prototypes is that a maintainer may make the mistake of modifying some of the code and calling a static function higher up in the file than it is defined, resulting in a call to a function that the compiler does not know about. I only use three of compilers regularly, but they all warn about this. Am I being naive to expect that all comercial compilers do.I think that the code is just as readable in both layouts. (Whichever layout, you will use the same strategy for understanding it, be it bottom-level up, top-level down, or come in via some design documentation.)Personally, I don't think it is a big deal which layout you use because I cannot see a strong technical argument that demonstrably makes one better than the other, but as I feel that the static prototypes don't add anything of value, I don't use them.Steve Huggins

  4. Nigel Jones says:

    An interesting rebuttal Steve. However I don't think it holds water."Not so; you are not constrained to read source code from top to bottom of the file."I'm not sure I agree. I am constrained to read a function from top to bottom (or at least it makes more sense that way!). As a result, reading code from bottom to top means that one has to go to the end of the file, page up until one finds a function header, then read down, then scroll up for the next function header and so on. Maybe it's just me, but this significantly impacts my ability to effectively browse the source code."No it's not. They are all at the bottom of the file. Electronically search by name if you need to (all the names should be in the .h file)."Well it's true that the end of the public functions is at the end of the file. But where is start of the public functions? I regularly want to know the answer to that question. I rarely want to know the answer to the first question. As for searching via the names in the header file. I can certainly do that if I'm looking for a specifc function. However it's not much use if I want to browse the code."Having prototypes for static functions just gives you lots more lines of code to maintain. When you alter the signature of a static function, and hence are making a change local to the one .c file, you will need to make two identical changes if you have a prototype for it at the top of the file, but only one change if there are no static prototypes."Well I don't see this as any different as to what you have to do with public functions. I think this also sums up nicely where I disagree with you. Your complaint is essentially that while you are writing code, prototyping static functions is an unnecessary and time consuming step – particularly if you have to change them (as one often does during development). For me that's the wrong way of looking at it. You should be considering the poor sod who will be maintaining the code years from now. IMHO you have saved yourself 30 seconds a function by avoiding prototyping – and cost the maintainer an incredible amount more. Where you'll disagree with me is that you obviously don't think that your layout style will cost the maintainer any more. Is this reasonable? Well I think we can run a rather unscientific experiment as follows:As it stands, there are three possible answers to this debate:1.Static functions should be placed at the end of the file.2.Static function position is irrelevant3.Static functions should be placed at the top of the file.We have myself and two commenters (to date) voting for 1. You would seem to be voting for 3. As it stands there are no votes for 2. Hopefully other folks will weigh in with their thoughts within the comments section. After a week or two we can look at the results. If we assign weights of +1, 0 and -1 to the three options and add up the scores, then IMHO if the result is positive (indicating that a plurality of folks prefer static functions to be at the end of the file), then the case is made. The converse of course applies.

  5. Anonymous says:

    While I would agree that there are good comments for, currently, both sides, most coders will "do their thing". I applaud the coder that actually makes the effort to make code clean, readable and maintainable. I would also like to add that a good editor would help in lessening the time to understand and help point out the different function types plus a whole lot more. One such editor is SlickEdit.As a side, I suppose this is an argument for #2, Static function position is irrelevant (when you have a good editor).

  6. Anonymous says:

    Interesting response Nigel. I read all comments with an open mind as I have no vested interests and am ready to change my working practices if presented with sufficiently persuasive arguments. However, I still think that this issue is largely a matter of personal style and don't feel swayed by what you say to change mine. (I spend about 75% of my time maintaining other people's and my own code, and 25% writing fresh code.)I agree with another commenter about the utility of a good editor when it comes to browsing source code. I realise now that I have come to take it a bit for granted, but the benefit cannot be emphasised enough. As it happens, I use Microsoft's Visual Studio 2005 editor which gives immensely useful facilities like:* right-clicking on an identifier and selecting 'Go To Definition'* the 'Code Definition Window' which displays the definition of whatever identifier you click on in the main editor window* Outlining (aka folding) – allowing you to 'collapse' (~hide) all function bodies (and other file-scope groupings), thereby showing you just the function signatures one after the other (from which you can quickly see where the static functions end and the public ones begin)* puting the cursor by a curly brace, keying Ctrl+] to jump to the other of the matching pair* being able to open a header file via a right-click of the #include line* Ctrl+- to navigate backwards* regular expression searchingand other sundry things like colour coding and intellisense.These facilities make browsing a source file about as easy as it can be made, leaving your brain to concentrate on the hard part – understanding what the code is doing.So the question arises, would I structure source code differently if I (and my colleagues) only had the most basic of text editors available? I don't think so. (I don't recall having to regularly ask myself where the start of the public functions is, so this isn't such an issue for me. I guess that I browse files differently from you Nigel.)Regarding maintenance, having coding standards would help. If it is stated up front that on this project this is the way that things are done (whatever way that is), then a maintainer would know whether or not they can count on all functions being known to the compiler before they are called and code accordingly.If the maintainer doesn't have the benefit of coding standards or fancy text editors, then shouldn't they check what the style of the file is before they go altering it? We should always code with a maintainer in mind, but at the end of the day, if we are coding in C then we can only do so much to help them. I don't think that any of the possible styles of placement of static functions guarantees a file to be more maintainable.Steve Huggins

  7. Anonymous says:

    My first post.. Voting for option no 2. There are more important things to make the code look more readable.Piotr Przybylek

  8. Steven N says:

    I strongly disagree with this advice and I think it promotes a very bad coding style. My single biggest complaint is maintaining multiple declarations of a static function greatly increase future maintenance issues. Why change things twice when a single definition in prototype form would have worked equally as well? I am not a fan of redundant unneeded code just for the sake of code.

    Likewise, I have worked at companies where the coding standards dictate public interface up front, static functions at the end and prototypes in a unique file. Now, you are forced to update and review multiple files for, what is effectively, a single file change.

Leave a Reply