Reputation: 137
What is the difference between these two function body codes? (The first code is from The C Programming Language book)
What's the difference between declaring the function and using it versus using it directly without declaring it first?
int atoi(char s[]) {
double atof(char s[]);
return (int) atof(s);
}
int atoi(char s[]) {
return (int) atof(s);
}
Upvotes: 2
Views: 129
Reputation: 17573
The first example of source code explicitly tells the compiler information that the compiler must infer in the second example of source code.
The following discussion makes the assumptions that the function atof()
is not declared or defined in any way (include file, etc.) before its use in the examples.
In the first example you have an explicit declaration of the function atof()
which allows the compiler to perform some checks that it is being used properly.
int atoi(char s[]) {
double atof(char s[]); // atof is a function that takes a character array and returns a double value
return (int) atof(s);
}
By the way I would declare this as extern double atof(char s[]);
just to make it clear to a human reader that this is an external function.
In the second example the compiler has to infer that atof()
is a function and that it takes a char
array. The compiler uses the source line and the argument types used in this call to an undefined and undeclared function to create the function declaration.
However the compiler doesn't know the type of return value of the function since the definition of the function is not available so to complete the generated declaration, the compiler uses the default of int
.
This compiler generated declaration is only generated for functions. Should an undefined or undeclared variable be used, the compiler will generate an error. The key to the decision as to whether it is a function, which may have a declaration generated, or a variable, which may not, is whether an open parenthesis follows the name or not.
int atoi(char s[]) {
return (int) atof(s);
}
The first example with an explicit declaration provides the compiler additional, explicit information that allows it to check the use of the function. The second example the compiler must make assumptions and generate a declaration which is then used to validate that the function is being used properly.
One problem that such a generated declaration can cause is if the first use of an undefined and undeclared function is incorrect, the declaration the compiler generates is also incorrect and should the function be used differently but correctly in the source code following, the compiler may generate a warning or error depending on what the actual differences between the two uses of the function, one incorrect and one correct, are.
The preferred procedure for functions that are being used in other source files is to provide a header or include file that goes along with the source code file containing the functions that are being used. In this header file would be declarations for all of the functions with external visibility (in other words that have not been declared static
in the source file) and this header file would be provided along with the object code or library file containing the compiled function definition.
Anyone using the function would then include the header file so as to allow the compiler to check that they are using the function properly. There are some checks that the compiler can not provide or which the programmer can work around but having the function declaration available provides a basic level of validity checking by static syntax checks by the compiler.
An Experiment
Experimenting with Visual Studio 2015, once a function is declared, even if within a function scope, the compiler remembers the declaration and uses that declaration as a check on any other uses following in the source file. Also if the function is used without a declaration, the compiler generates a declaration that it then checks against for any other places where the function is used.
This behavior of remembering a function declaration is a bit different than if an external variable is declared within a function scope. An external variable declaration is only visible within the scope it is declared within. Also if the same variable name exists in a higher level of scope encapsulating this new scope (created using a left brace or an open brace), the new declaration overrides the previous declaration within the new scope. Once the new scope ends (using a right brace or a closing brace) the original declaration becomes visible again.
For example in the following source code, the declaration of the function atof1()
declared in the first function is used to validate the use of the function atof1()
in the second function. In addition the compiler creates a declaration for the function atof2()
when it comes across the function being used and it is not declared and this created declaration is used to perform a validity check for any other instance of use of the function atof2()
.
int xatoi(char s[]) {
extern double atof1(char s[]); // atof is a function that takes a character array and returns a double value
extern double jj;
jj = atof1(s); // line 106
jj = atof2(s); // line 107, undeclared undefined function, compiler creates declaration, assumes function returns int
return (int)jj; // line 108
}
int xato2(char s[])
{
int kk; // line 113
jj = atof1(s); // line 114, variable jj is declared in function above but not in this one.
kk = atof1(s); // line 115, double value returned by atof1() is converted to int
kk = atof2(s); // line 116, compiler uses created declaration to check and atof2() is assumed to return an int
jj = atof1(s, 3); // line 117, this use of atof1() does not match the declaration of atof1() in function xatoi() above.
return (int)jj; // line 118
}
The above code generates the following warnings and errors in Visual Studio 2015.
1>mldmodd.c(107): warning C4013: 'atof2' undefined; assuming extern returning int
1>mldmodd.c(114): error C2065: 'jj': undeclared identifier
1>mldmodd.c(114): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
1>mldmodd.c(115): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
1>mldmodd.c(117): error C2065: 'jj': undeclared identifier
1>mldmodd.c(117): warning C4020: 'atof1': too many actual parameters
1>mldmodd.c(117): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
1>mldmodd.c(118): error C2065: 'jj': undeclared identifier
Upvotes: 3