Think of it this way. The content of the included file is simply inserted at the point in the file where the #include directive appears. The resulting code needs to be syntactically correct for the language that you are programming in.
Confider the following file:
int a;
int foo();
int main()
#include "myheader.h"
int foo()
{
return 0;
}
And the file myheader.h contains:
{
return foo();
}
The code that the compiler will see after the preprocessor has processed the #include directive is:
int a;
int foo();
int main()
{
return foo();
}
int foo()
{
return 0;
}
This is valid C syntax. Such use of the #include directive is not recommended, but it gives you an idea of what it means. If the myheader.h file had the following content:
this is some garbage
which is not proper C
Then the resulting code will be:
int a;
int foo();
int main()
this is some garbage
which is not proper C
int foo()
{
return 0;
}
You can use #include at any point in the file. It results in literal inclusion of the content of the included file at that point. The reason you get a undeclared message for printf() in your code is that C requires a function be declared before use, and stdio.h has that declaration. Which is why it needs to be before it's use. And why it cannot be included in main() in the latter example is because on inclusion (expansion), it results in syntactically incorrect C code.