Reputation: 1204
I assumed that one of the most used system functions (ls
) of one of the most famous OSs (linux) written by one of the most authoritative programmers (Richard Stallman) could be an example of really well written code.
So, being it open source, I decided to have a look at the code (see e.g. here). There I found several functions defined after the main()
, hence after their call, which I expected to be quite uncommon.
Will any experienced C programmer comment on this?
Upvotes: 3
Views: 10736
Reputation: 13551
There's absolutely nothing wrong with what Stallman did here.
The C language permits the forward declaration of a function that will be defined afterwards.
This has many advantages, and should not be considered as bad behavior, but rather very good behavior.
Advantages (not exhaustive):
- give the programmer a vision of the API exposed by the C code in a quick look, without having to look at all the code
- permits the use of header files, where you declare a function that will be defined later on in the compilation process. So that you don't have to define your function every time you use it..
In the case of this ls
implementation, he simply pre-declared the functions that he'll use in the main()
, but if you look carefully, the main function is the first one to appear.
This is most probably for the sake of readability, so that you don't have to scroll all the way down to reach the entry point of the program.
Note that the vocabulary is important here:
- function declaration means: just tells the compiler that, somewhere in your code, a function with the same name will be defined.
- function definition : the actual function implementation
int my_function( char *text); // function declaration, no implementation
int main( int argc, char **argv)
{
return my_function(argv[0]); // use of the declared function
}
// actual function definition / implementation
int my_function( char *text )
{
printf("%s\n", text);
}
Edit: after looking more carefully to the code, you can see that Stallman didn't forward-declare all his functions. He has also a rather strange manner of defining functions. I attribute this to the oldness of the code, which is dated of 1985, when the C compiler was not as well defined as today. It must have permitted this kind of function usage before being declared or defined.
Last but not least, the recent version of ls
source code can be found here: http://coreutils.sourcearchive.com/documentation/7.4/ls_8c-source.html ,
with much more C99-compliant coding than the '85 (Back-to-the-Future) version.
Upvotes: 11
Reputation: 32953
For me this is a relic from the pre-prototype era, have a look at newer code and quite often you'll see an inverted code order. The main disadvantage for me is that you have to declare the function on top, and then the function itself way down. If you change the function's signature you'll also have to change in 2 locations. Please note that this is also the case for static functions, a feature that was not used in this piece of code at all... Sure the thing will compile if you don't but you'll get bitten by C's implicit declarations earlier or later.
Seriously, find yourself some more recent code than some oldskool K&R style C, the C language has evolved considerably since then, you might pick up a couple of bad habits in the process.
Upvotes: 2
Reputation: 108978
You need to have a prototype in scope before calling the function. A function definition serves as prototype
/* this is a definition and a prototype */
int fx1(void) {
return 42;
}
/* this is only a prototype */
int fx2(int, const char*);
int main(void) {
fx1(); /* ok, prototype in scope */
fx2(42, "foobar"); /* ok, prototype in scope */
}
/* fx2 definition.
** it is undefined behaviour if the prototype here
** does not match the previous prototype */
int fx2(int k, const char *t) {
return strlen(t) - k;
}
Often, prototypes are declared in header files, which are included at the top of implementation files, before any code.
#include "prototypes.h"
/* define functions in any order: prototypes are all in scope */
Upvotes: 1
Reputation: 6919
In C you usually define function prototypes in header files, then include the header files, so functions can safely be defined after they are called.
In the example file you provided the program is sufficiently small that the prototypes are simply put at the top of the file, before the procedure declarations, but the same principle applies.
EDIT: Also, that file is pre-K&R C, which is kinda cool but there are some significant differences to modern C, you should not necessarily imitate it.
Upvotes: 5
Reputation: 506955
The code will conceptionally read like a nice specification
main
).That he omits declarations of the functions to be put before main
(to satisfy first bullet - defining the interface) is considered bad style by many programmers regarding modern C.
The code however uses old-style function definitions, for which their declarations don't define parameter types to the caller. Presumably, updating this code to be modern C would break a lot of very old systems that still use pre-ANSI compilers.
Upvotes: 2