S:\mcu\blink_led\main.c:4:Warning [2058] call of function without prototype
.
.
.
BUILD SUCCEEDED
We are almost ready to add some useful code to our project but first I want to cover a couple of basics about functions and prototypes. We will be making frequent use of functions as we move forward so I feel it is important that you know some best practices for their use, how bypassing these best practices can cause build errors, and why some dirty code only throws a warning and not an error.
A function prototype is a way of informing the compiler that somewhere in the program there will be this specific function, what type of data it will expect (if any) and what type of data it will return (if any). The first instance of a function, whether it be a prototype, it's use, or the actual function determines its logic (as mentioned above). In some instances where you have a function that doesn't expect anything and doesn't return anything, using it somewhere in the program will probably cause the compiler to throw a warning during the build. If the function returns something and/or expects something, a serious type mismatch can occur and the build will fail. So pay attention to prototype warnings that may appear in your build output and address them right away. Creating a prototype insures that the compiler knows what the function is all about before any code is encountered so occurrences of the function call throughout your code can be properly validated by the compiler, giving you an error-free build.
Here are some examples of this behavior. Hopefully, these examples will help you debug some of these common build errors and shed some light on why they occur. I'll leave out the pragma directives included in our main.c file to shorten and simplify the examples.
This first example shows why a build warning occurs. A prototype isn't used and the function doesn't expect or return anything.
1 2 3 4 5 6 7 8 |
#include <p18f452.h> void main(void){ testfunction(); } int testfunction(void){ } |
The first occurrence of the function is encountered in the form of a call within main on line 4 instead of the actual function on line 7 or a prototype, so the function is assumed to be of the type INTEGER even though the compiler isn't sure, thus the warning. These are usually non-lethal to code execution but it leaves a possible problem that can alter the program's results later on.
The build output...
S:\mcu\blink_led\main.c:4:Warning [2058] call of function without prototype
.
.
.
BUILD SUCCEEDED
Since the function is indeed of type INTEGER, the build is allowed to succeed.
But say we change the testfunction to be of type CHAR, as in...
1 2 3 4 5 6 7 8 |
#include <p18f452.h> void main(void){ testfunction(); } char testfunction(void){ } |
'testfunction' is first encountered in main on line 4 and assumed to be of type INTEGER, but when the compiler encounters the actual function on line 7, it is of type CHAR instead so there will be a type mismatch and the build will fail.
The build output...
S:\mcu\blink_led\main.c:4:Warning [2058] call of function without prototype S:\mcu\blink_led\main.c:7:Error [1109] type mismatch in redeclaration of 'testfunction' Halting build on first failure as requested. . . . BUILD FAILED
1 2 3 4 5 6 7 8 9 10 |
#include <p18f452.h> char testfunction(void); void main(void){ testfunction(); } char testfunction(void){ } |
The function is revealed to the compiler in the form of a prototype on line 3 so when it is encountered later on, on lines 6 and 9, the compiler knows that the function is of type CHAR and no mismatches will occur.
The build output...
. . . BUILD SUCCEEDED
As you can see, function prototypes are very important to writing safe and succesful code. They are very simple to do as well. When I write a function, I make a habit of prototyping it before I leave it to work elsewhere. You can prototype it first, but if you change the arguments it expects, or decide on another data type for it, you will have to make sure you change that prototype to reflect the changes. The prototype is exactly like the function header except the line is ended with a semicolon instead of an open curly brace.
So why doesn't main need a prototype? I'm not really sure, but it seems logical that since it is the first function header encountered and isn't called that no errors are thrown when main isn't prototyped. Advanced programming techniques I haven't yet encountered might require main to be prototyped so prototyping main is probably a good idea and certainly doesn't hurt anything. I never have though and have yet to encounter an error because of it.