C unnecessary function prototypes

Consider these styles for a single source file program.

Form 1
Code:
void A(int x, int y);
int B(float x);

int main(int argc, const char *argv[])
{
    A(1, 2);
    return B(3.f);
}

void A(int x, int y)
{
    // some code goes here.
}

int B(float x)
{
    // do something with x
    return 0;
}

Form 2
Code:
void A(int x, int y)
{
    // some code goes here.
}

int B(float x)
{
    // do something with x
    return 0;
}

int main(int argc, const char *argv[])
{
    A(1, 2);
    return B(3.f);
}

Form 3
Code:
static void A(int x, int y)
{
    // some code goes here.
}
static int B(float x)
{
    // do something with x
    return 0;[/ICODE]
}

int main(int argc, const char *argv[])
{
   A(1, 2);
   return B(3.f);
}
I personally prefer form 3 above. Form 1 violates the DRY or don't repeat yourself principle. I see quite a bit of code using form 1 which doesn't actually need prototypes and also exports the symbols to the linker instead of marking them as static and file scope. If you add or remove parameters to functions A or B - or change the return type - you need to remember to touch both locations. Why incur the risk?

Unless I have a pair of codependent functions, I can usually avoid the prototype.

As before, no reply needed. I just like to complain. :rolleyes:
 
I prefer form 3 as well, but to each their own. There are people who can't look at their code without getting mad if functions are not sorted alphabetically (for binary search). Others who just love to have references in a legible list and see no reason they could not have that for static functions. Others who laugh at the idea that anyone is taking seriously the fact that functions order matter in C. Live and let live, they do whatever they want in _their_ codebase.

(I find very hard to defend form 2 instead of form 3, though… 😅 But I guess there will be people having reasons for that)
 
Header files, especially if the function is meant to be publicly visible.
Static means "reference does not exist outside this object file" (at least in C, not C++, but it can mean that in C++)
Although B doesn't really need to do anything with X because X is not modifiable in B (pass by value not by reference I think is the correct term)


Don't more current version of C standard let you get form 3 by doing:

int main(int argc, const char *argv[])
{
void A(int x, int y)
{
// some code goes here.
}

int B(float x)
{
// do something with x
return 0;
}
A(1, 2);
return B(3.f);
}
 
static for a function means it can't be used outside the current file, it's private API (and you can define static functions with the same name elsewhere in the codebase). That's also the point of putting the prototype at the top of file rather than in a header file: it allows to have prototypes, not having to bother with the order of functions, while still marking clearly that other files are not supposed to use this function (and enforcing they can't).
 
Static means "reference does not exist outside this object file" (at least in C, not C++, but it can mean that in C++)
The question was why the author wants to make all functions static. If it was preferrable, all functions would be static by default (plus another keyword for non-static).
 
There are people who can't look at their code without getting mad if functions are not sorted alphabetically (for binary search).
This is actually a requirement of style(9). It does make finding a function a little easier. Quoting style(9):

All functions are prototyped somewhere.

Function prototypes for private functions (i.e., functions not used
elsewhere) go at the top of the first source module. Functions local
to one source module should be declared static.

The downside is the duplication of text with the slight risk of not keeping them in sync. For projects outside the FreeBSD source tree, I prefer not to follow this. Note that style(9) does mandate static where appropriate.

Some other reasons for encouraging static are:
  • fewer symbols for the linker
  • less risk of symbol collisions
  • hiding implementation details prevents API abuse where some code elsewhere starts using the internet bits - making future re-design/refactor harder.
 
Don't more current version of C standard let you get form 3 by doing:
I've not seen nested functions in C. Apparently GCC allows this but it is not in the standard. No idea if clang allows this. Apparently this feature carries some elevated risks of stack and overflow attacks.
 
My style has always been to explicitly do function prototypes at the top (or in header file if they are exportable)

Then alphabetize the functions, separating them with
//----------------------------------------------------------------------------------
lines

and finally

// =======================================================
// =======================================================
// =======================================================
int main (int argc, char* argv[]) {
return 0;
}

This gives me good visual queus to know where functions break, and always
expect main() at the bottom

I'm also a huge advocate of requiring real and useful doxygen markups, but
equally annoying is a program that is more comments than it is real code.
 
I've not seen nested functions in C. Apparently GCC allows this but it is not in the standard. No idea if clang allows this. Apparently this feature carries some elevated risks of stack and overflow attacks.
Even in C++ I try to avoid nested functions. Object declarations...sure, but nested functions are often better implemented as lambdas in C++.
 
Back
Top