Reputation: 133
Here is some sample code that will resemble an issue I am having
#include <stdio.h>
int cube_then_square(int x){
x = cube(x);
return x*x;
}
int cube(int y){
return y*y*y;
}
int main(int argc, char *argv[]){
printf("5 cubed then squared is: %d\n", cube_then_square(5));
return 0;
}
So the compiler gives me an issue with cube
being undeclared. So can somebody please explain the order in which these functions are put in memory, etc...and how it would be different from putting the prototypes on top and the implementations after main
.
Upvotes: 0
Views: 2080
Reputation: 320671
It is completely irrelevant how these functions are "put in memory". In fact, this is in no way exposed at the language level. It does not matter.
When you are organizing an implementation file, you have a choice of doing it in either top-down fashion or bottom-up fashion.
In the former case upper-level functions are defined first. Upper-level functions call lower-level functions, which are defined later in the file. In order for that to work properly, the low-level functions have to be additionally prototyped before the point of the first call (e.g. at the very top of the file). (Formally, a prototype is not required, but at least a declaration is required.)
In the latter case lower-level functions are defined first and upper-level functions are defined later. In this approach the definitions themselves already serve as prototypes, meaning that no additional prototyping is required (unless you have a circular call dependency between functions).
Top-down is a higher maintenance approach, since you have to keep function prototypes in sync with their definitions.
What you have in your example looks like a mix of these two approaches. main
(the highest-level function) is defined at the bottom, yet cube_then_square
is defined before cube
. There's nothing really wrong with that, but to keep this ordering you have to provide a prototype for cube
at the beginning of the file.
I personally prefer the bottom-up approach. E.g. in your specific example I'd move the entire definition of cube
to the top of the file. That would eliminate the need to provide an additional prototype.
In any case, regardless of how you do it, there's no meaningful difference in the generated code. The ordering of functions in the object file might be affected by their ordering in the source file, but this is completely inconsequential from the language point of view.
Upvotes: 0
Reputation: 2007
The warning of an implicitly declared function exists because most modern C programs don't use implicit functions.
Old C89 allowed for implicitly declared everything. When you call a function it gets implicitly declared as int func ()
.
This works in this situation because you implicitly declare the function int cube()
with the line:
x = cube(x);
and then later you define the function int cube(int)
. int cube()
and int cube(int)
have compatible types so this is a fine call to make.
The trouble you can really run into is calling an incompatible function from an implicitly declared function (this is really why the warning exists). int cube(float)
is an incompatible function type that could definitely exist and if you called it with an implicitly declared function you could probably expect some pretty strange effects (read undefined). As mafso mentioned strict C99 no longer allows implicitly declared functions which is why many compilers include the warning regardless.
Remember implicitly declared function are BAD PRACTICE but you should know the exist for scenarios like this.
Here's a little program to demonstrate the weakness of implicitly declared functions. It takes advantage of some of the conversion rules you would expect in a c program that suddenly go away with implicitly declared functions.
#include <stdio.h>
cube1(int x){return x*x*x;}
main(){float y = 9.; printf("%d\n%d\n", cube1(y), cube2(y));}
cube2(int x){return x*x*x;}
output:
729
1
These functions are identical in the asm
00000000004004dc <cube1>:
4004dc: 55 push %rbp
4004dd: 48 89 e5 mov %rsp,%rbp
4004e0: 89 7d fc mov %edi,-0x4(%rbp)
4004e3: 8b 45 fc mov -0x4(%rbp),%eax
4004e6: 0f af 45 fc imul -0x4(%rbp),%eax
4004ea: 0f af 45 fc imul -0x4(%rbp),%eax
4004ee: 5d pop %rbp
4004ef: c3 retq
0000000000400540 <cube2>:
400540: 55 push %rbp
400541: 48 89 e5 mov %rsp,%rbp
400544: 89 7d fc mov %edi,-0x4(%rbp)
400547: 8b 45 fc mov -0x4(%rbp),%eax
40054a: 0f af 45 fc imul -0x4(%rbp),%eax
40054e: 0f af 45 fc imul -0x4(%rbp),%eax
400552: 5d pop %rbp
400553: c3 retq
But at the callsite the expected conversion from float to integer is never performed for the implicit call.
Upvotes: 5
Reputation: 27812
To fix this problem, you can declare cube
before using it:
#include <stdio.h>
int cube(int y){
return y*y*y;
}
int cube_then_square(int x){
x = cube(x);
return x*x;
}
int main(int argc, char *argv[]){
printf("5 cubed then squared is: %d\n", cube_then_square(5));
return 0;
}
You can also add the function header int cube(int y);
at the top:
#include <stdio.h>
int cube(int y);
int cube_then_square(int x){
x = cube(x);
return x*x;
}
int cube(int y){
return y*y*y;
}
int main(int argc, char *argv[]){
printf("5 cubed then squared is: %d\n", cube_then_square(5));
return 0;
}
Upvotes: 0
Reputation: 869
To the top of your file, under the includes, add int cube(int y);
You have to declare a function before you use it. It doesn't have to be defined yet, but it has to be declared before it is used, because the compiler checks lines in sequential order.
Upvotes: 1
Reputation: 1835
The compiler reads the file from top to bottom. When it reaches function, it checks whether it already knows it. In this case it hasn't seen the function cube(int)
, so it returns an error.
You can do two things:
1. You move the function cube
before the function cube_then_square
.
2. You create a forward declaration before cube_then_square
:
int cube(int y);
Upvotes: 1