What will happen when a function defined within another function? What is the difference between code 1 and code 2?
CODE 1:
#include<stdio.h>
void m();
void main()
{
m();
void m()
{
printf("hi");
}
}
CODE 2:
#include <stdio.h>
void m();
void main()
{
void m()
{
printf("hi");
}
m();
}
When I compiled code 1 in gcc compiler, I got linkage error. But when I compiled code 2, I didn't get any error. I got output "hi". I want to know how compilation is done, when we write function definition within another function. I know that when we write function definitions not within another function, wherever be the function definition, we will not get any error when we call that function. for example see the below code:
CODE 3:
#include <stdio.h>
void m();
void main()
{
m();
}
void m()
{
printf("hi");
}
In code 3,even though I called the function before definition, it didn't show any error and I got output. Why it is not happening with code 1.
Neither C nor C++ allows to define a function within another function. So it seems you are using a special language extension of compiler GCC that allows to define local functions inside another functions.
In the first program function m is declared in file scope. So its definition will be searched by the compiler in the file scope. When the function is called inside main only this file scope declaration is visible. However the compiler did not find its file scope definition so it issued an error.
In the second program there is also a declaration of function m in the file scope. However inside function main there is another declaration of function m that has block scope and hides the declaration with the file scope. Take into account that a definition also is a declaration. So the call of m refers to the function m that is declared inside main and has block scope. The compiler has the function definition and can call it.
in the third program that satisfies the C Standard inside main the call of m refers to the function m declared in the file scope and there is a definition of this function in the file scope. So there is no any problem.
You can not define functions inside function. It is not allowed in C and thus won't compile. Code snippet 1 and 2 are invalid and only snippet 3 is valid ANSI C code.
Why code 1 does not compile and code 2 compiles well in gcc
Code 2 compiles under gcc because of a GNU compiler extension. You must declare the function before first usage for this extension to work.
Then why does code 3 compiles
In Snippet 3, you are declaring the function before first usage which is enough for compiler to place the required code. At linking time, required linking with the definition code is required. There is no necessity from linker about the placing of definition (In ISO C specifcations), the function definition is allowed to present even in a separate compilation unit.
It's a scope problem. In your CODE 1 sample, the m function is only visible within the main function. So the function header you put before the main (void m();) expect a global m function and did not find it, that's why you have a link error. In your code 2 sample, the m function is found because it's written before the call, your global m function is still not present but not used => you don't have the link error. In your code 3 sample, your m function is global and then found as expected by the header => no error
In code 3, even though I called the function before definition, it didn't show any error and I got output. Why it is not happening with code 1?
Code 3 is conforming standard C code. A function with external linkage can be called wherever a declaration is visible (provided a definition exists somewhere in the programme, it doesn't have to be in the same file).
When I compiled code 1 in gcc compiler, I got a linkage error.
Nested functions are a GCC extension:
A nested function always has no linkage. Declaring one with extern or static is erroneous. If you need to declare the nested function before its definition, use auto (which is otherwise meaningless for function declarations).
At the point m is called, an external declaration (the file scope declaration void m();) is visible. As there is no external definition in this source file, gcc assumes it is in another translation unit, and eventually the linker fails finding it. According to the quoted documentation, a valid version could be
#include <stdio.h>
int main(void)
{
auto void m(); /* Hides the outer declaration. */
m(); /* Refers to the nested function, not to an external one now. */
void m()
{
printf("hi");
}
}
But when I compiled code 2, I didn't get any error. I got output "hi".
At the point, where m is called, the nested function is visible, hiding the file-scope declaration. The file-scope declaration (declaring a function with external linkage) is never used, so the linker doesn't try to resolve a call to it.
A conforming implementation may accept a declaration of main as a function returning void, but doesn't have to. Old-style (or K&R-style) declarations and definitions are obsolescent in C89, C99 and C11, so it's better to use
int main(void);
void m(void);
Check the link below:
Nested function in C
C doesn't support nested functions so your Code Snippet 1 and 2 are not allowed standards though you might see code snippet 2 working because you have function call after function definition.
The only allowed snippet is Code 3 the rest should not be done in C .
GCC special extensions:
https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html
You are not compiling your code as standard C. GCC is tricky because it comes with crappy non-standard settings by default. To use GCC as a proper C compiler, you must do gcc -std=c11 -pedantic-errors, where c11 is the preferred standard (switch to c99 if you have an old version of GCC). While you are at it, ensure to enable all warnings too:
gcc -std=c99 -pedantic-errors -Wall -Wextra
Now that the compiler is configured to be a C compiler, we get the following errors:
CODE1 and CODE2:
error: return type of 'main' is not 'int' [-Wmain].
This error comes because when GCC is set to be a C compiler, it is not providing an implementation-defined way to specify main. You have to change main to int main (void).
error: ISO C forbids nested functions [-Wpedantic]
This error comes because nested functions aren't allowed by the C standard. You got away with it before, because you had GCC set to be a non-standard compiler.
Related
I have gone through following questions:
Global variable in C are static or not?
Are the global variables extern by default or it is equivalent to declaring variable with extern in global?
Above links describe that if we define global variable in one file and haven't specified extern keyword they will be accessible in another source file because of translation unit.
Now I have file1.c in that have defined following global variable and function:
int testVariable;
void testFunction()
{
printf ("Value of testVariable %d \n", testVariable);
}
In file2.c have following code
void main()
{
testVariable = 40;
testFunction();
}
Now I am getting error: 'testVariable' undeclared (first use in this function) -- why?
Note: both files are used in same program using makefile.
As per my understanding both function and global variable have default external linkage. So function we can use directly by it's name in another file but variable can't why?
Can any one have idea?
EDIT:
From the below answer i get idea that like in case of function old compiler will guess and add an implicit declaration but in case of variable it can't. Also C99 removed implicit declaration but still I am getting warning in C99 mode like:
warning: implicit declaration of function ‘testFunction’.
Now have gone through below link:
implicit int and implicit declaration of functions with gcc compiler
It said that compiler take it as diagnostic purpose and not give error. So compiler can process forward.
But why in case of variable it can't process further? Even in case of function if compiler proceed and if actual definition not there then at linking time it will fail. So what's benefit to move forward??
There are two things in play here: The first is that there is a difference between a definition and a declaration. The other thing is the concept of translation units.
A definition is what defines the variable, it's the actual place the variable exists, where the compiler reserves space for the variable.
A declaration is needed for the compiler to know that a symbol exists somewhere in the program. Without a declaration the compiler will not know that a symbol exists.
A translation unit is basically and very simplified the source file plus all its included header files. An object file is a single translation unit, and the linker takes all translation units to create the final program.
Now, a program can only have a single definition, for example a global variable may only exist in a single translation unit, or you will get multiple definition errors when linking. A declaration on the other hand can exist in any number of translation units, the compiler will use it to tell the linker that the translation references a definition in another (unknown at time of compilation) translation unit.
So what happens here is that you have a definition and a declaration in file1.c. This source file is used as input for one translation unit and the compiler generates a single object file for it, say file1.o. In the other source file, file2.c, there is no definition nor any declaration of the global variable testVariable, so the compiler doesn't know it exists and will give you an error for it. You need to declare it, for example by doing
extern int testVariable; // This is a declaration of the variable
It's a little more complicated for the function, because in older versions of the C standard one didn't have to declare functions being used, the compiler would guess and add an implicit declaration. If the definition and the implicit declaration doesn't match it will lead to undefined behavior, which is why implicit function declarations was removed in the C99 standard. So you should really declare the function too:
void testFunction(void); // Declare a function prototype
Note that the extern keyword is not needed here, because the compiler can automatically tell that it's a function prototype declaration.
The complete file2.c should then look like
extern int testVariable; // This is a declaration of the variable
void testFunction(void); // Declare a function prototype
void main()
{
testVariable = 40;
testFunction();
}
When compiler copes with file2.c it knows nothing about existence of testVariable and about its type. And as result it can't generate code to interact with such object. And purpose of line like
extern int testVariable;
is to let compiler to know that somewhere such object exists and has type of int.
With functions we have no such problem because of next rule - if function is not defined - compiler assumes that it is defined somewhere like
int testFunction() { ... }
So you can pass any number of any arguments to it and try to obtain int return value. But if real function signature differs - you'll get an undefined behafiour at runtime. Because of this weakness such approach is considered as bad practice, and you should declare proper function prototype before any call to that func.
Recently I've learnt about implicit function declarations in C. The main idea is clear but I have some troubles with understanding of the linkage process in this case.
Consider the following code ( file a.c):
#include <stdio.h>
int main() {
double someValue = f();
printf("%f\n", someValue);
return 0;
}
If I try to compile it:
gcc -c a.c -std=c99
I see a warning about implicit declaration of function f().
If I try to compile and link:
gcc a.c -std=c99
I have an undefined reference error. So everything is fine.
Then I add another file (file b.c):
double f(double x) {
return x;
}
And invoke the next command:
gcc a.c b.c -std=c99
Surprisingly everything is linked successfully. Of course after ./a.out invocation I see a rubbish output.
So, my question is: How are programs with implicitly declared functions linked? And what happens in my example under the hood of compiler/linker?
I read a number of topics on SO like this, this and this one but still have problems.
First of all, since C99 , implicit declaration of a function is removed from the standard. compilers may support this for compilation of legacy code, but it's nothing mandatory. Quoting the standard foreword,
remove implicit function declaration
That said, as per C11, chapter §6.5.2.2
If the function is defined with a type that does not include a prototype, and the types of
the arguments after promotion are not compatible with those of the parameters after
promotion, the behavior is undefined.
So, in your case,
the function call itself is implicit declaration (which became non-standard since C99),
and due to the mismatch of the function signature [Implicit declaration of a function were assumed to have an int return type], your code invokes undefined behavior.
Just to add a bit more reference, if you try to define the function in the same compilation unit after the call, you'll get a compilation error due to the mismatch signature.
However, your function being defined in a separate compilation unit (and missing prototype declaration), compiler has no way to check the signatures. After the compilation, the linker takes the object files and due to the absence of any type-checking in the linker (and no info in object files either), happily links them. Finally, it will end up in a successful compilation and linking and UB.
Here is what is happening.
Without a declaration for f(), the compiler assumes an implicit declaration like int f(void). And then happily compiles a.c.
When compiling b.c, the compiler does not have any prior declaration for f(), so it intuits it from the definition of f(). Normally you would put some declaration of f() in a header file, and include it in both a.c and b.c. Because both the files will see the same declaration, the compiler can enforce conformance. It will complain about the entity that does not match the declaration. But in this case, there is no common prototype to refer to.
In C, the compiler does not store any information about the prototype in the object files, and the linker does not perform any checks for conformance (it can't). All it sees is a unresolved symbol f in a.c and a symbol f defined in b.c. It happily resolves the symbols, and completes the link.
Things break down at run time though, because the compiler sets up the call in a.c based on the prototype it assumed there. Which does not match what the definition in b.c looks for. f() (from b.c) will get a junk argument off the stack, and return it as double, which will be interpreted as int on return in a.c.
How are programmes with implicitly declared functions are linked? And what happens in my example under the hood of compiler/linker?
The implicit int rule has been outlawed by the C standard since C99. So it's not valid to have programs with implicit function declarations.
It's not valid since C99. Before that, if a visible prototype is not available then the compiler implicitly declares one with int return type.
Surprisingly everything is linked successfully. Of course after
./a.out invocation I see a rubbish output.
Because you didn't have prototype, compiler implicitly declares one with int type for f(). But the actual definition of f() returns a double. The two types are incompatible and this is undefined behaviour.
This is undefined even in C89/C90 in which the implicit int rule is valid because the implicit prototype is not compatible with the actual type f() returns. So this example is (with a.c and b.c) is undefined in all C standards.
It's not useful or valid anymore to have implicit function declarations. So the actual detail of how compiler/linker handles is only of historic interest. It goes back to the pre-standard times of K&R C which didn't have function prototypes and the functions return int by default. Function prototypes were added to C in C89/C90 standard. Bottom line, you must have prototypes (or define functions before use) for all functions in valid C programs.
After compiling, all type information is lost (except maybe in debug info, but the linker doesn't pay attention to that). The only thing that remains is "there is a symbol called "f" at address 0xdeadbeef".
The point of headers is to tell C about the type of the symbol, including, for functions, what arguments it takes and what it returns. If you mismatch the real ones with the ones you declare (either explicitly or implicitly), you get undefined behavior.
I have this snippet of code:
int foo1(void); //line a
int foo2(void) {
return foo1();
}
int foo1(void) { //line b
return 99;
}
If I want to declare function foo1 to be static, should I put the keyword static in line a or line b? Is there any difference?
Also say I have the following code in ANOTHER file that uses foo1 in the above file:
static int foo1(void);
int main(void) {
return foo1();
}
The code still compiles and works as expected although I put static in the declaration line. But it gives a warning saying that 'foo1' used but never defined - if it's not defined, why does the code still work?
Edit:
Sorry I didn't make that clear, for the second question, foo1 in the first file where it's defined is not declared as static, but I declare it as static in the second file.
In the first case, you need to put static on both line a and b. Static functions in C has internal linkage meaning that they are only visible in the same file. So for declaration and definition, you need to put static so that compiler knows that the function has internal linkage. If you don't put static on line a, you will get some compilation errors.
In the second case, since foo1 is a static function, it must be defined in the same file as main. You only put a forward declaration without actual definition. Even though it compiles fine, the program will not link since foo1 is not defined.
The static keyword in this context specifies that foo1 not be exported, so that particular foo1 could only be defined in that same compilation module, hence the warning when it isn't. (Without the static the code would be correct, assuming you mean to link the foo1 from the other file.)
As for why it works regardless of this, my guess is that the compiler falls back on looking for the external function, which it finds from your other file, but I think a conforming compiler would be justified in giving an error here.
In C static for functions means internal linkage and use of the function only within the scope of the file.
Interesting that compilers behave differently:
Snippet 1:
GCC and clang requires putting static in declaration (line a), in definition (line b) it can b omitted then.
In MS VC you can put static in declaration or in definition only, this makes foo1() static.
Snippet 2 (static foo1 in main.c, non-static declaration in other file):
GCC compiles static declaration without definition. clang compiles but outs a warning. (Both link then.)
MS VS does not compile the second snippet at all, giving an error C2129.
So, put static in both declaration and definition for clarity, and define static functions in the files where they are declared. Put forward declarations if required before usage of the functions.
Overall, seems that clang has better diagnostics.
"...if it's not defined, why does the code still work?"
In C it is not required to declare prototype before function call. The definition is than found on the linkage step.
I'm trying to compile the same C file on two different machines with different versions of cc.
gcc version 3.2.3 says warning: 'foo' was declared implicitly 'extern' and later 'static'
gcc version 4.1.2 says error: static declaration of 'foo' follows non-static declaration
Both have the same CFLAGS. I'd like to make gcc 4.1.2 behave like gcc 3.2.3, that is, find an option that would turn this error into a mere warning.
From what the error message complains about, it sounds like you should rather try to fix the source code. The compiler complains about difference in declaration, similar to for instance
void foo(int i);
...
void foo(double d) {
...
}
and this is not valid C code, hence the compiler complains.
Maybe your problem is that there is no prototype available when the function is used the first time and the compiler implicitly creates one that will not be static. If so the solution is to add a prototype somewhere before it is first used.
I have had this issue in a case where the static function was called before it was declared. Moving the function declaration to anywhere above the call solved my problem.
Try -Wno-traditional.
But better, add declarations for your static functions:
static void foo (void);
// ... somewhere in code
foo ();
static void foo ()
{
// do sth
}
While gcc 3.2.3 was more forgiving of the issue, gcc 4.1.2 is highlighting a potentially serious issue for the linking of your program later. Rather then trying to suppress the error you should make the forward declaration match the function declaration.
If you intended for the function to be globally available (as per the forward declaration) then don't subsequently declare it as static. Likewise if it's indented to be locally scoped then make the forward declaration static to match.
This error can be caused by an unclosed set of brackets.
int main {
doSomething {}
doSomething else {
}
Not so easy to spot, even in this 4 line example.
This error, in a 150 line main function, caused the bewildering error: "static declaration of ‘savePair’ follows non-static declaration". There was nothing wrong with my definition of function savePair, it was that unclosed bracket.
You have declared a function as nonstatic in some file and you have implemented as static in another file or somewhere in the same file can cause this problem also.
For example, the following code will produce this error.
void inlet_update_my_ratio(object_t *myobject);
//some where the implementation is like this
static void inlet_update_my_ratio(object_t *myobject) {
//code
}
If you remove the static from the implementation, the error will go away as below.
void inlet_update_my_ratio(object_t *myobject) {
//code
}
I had a similar issue , The function name i was using matched one of the inbuilt functions declared in one of the header files that i included in the program.Reading through the compiler error message will tell you the exact header file and function name.Changing the function name solved this issue for me
I have gone through some posts related to this topic but was not able to sort out my doubt completely. This might be a very naive question.
I have a header file inline.h and two translation units main.cpp and tran.cpp.
Details of code are as below
inline.h
#ifndef __HEADER__
#include <stdio.h>
extern inline int func1(void)
{ return 5; }
static inline int func2(void)
{ return 6; }
inline int func3(void)
{ return 7; }
#endif
main.c
#define <stdio.h>
#include <inline.h>
int main(int argc, char *argv[])
{
printf("%d\n",func1());
printf("%d\n",func2());
printf("%d\n",func3());
return 0;
}
tran.cpp
//(note that the functions are not inline here)
#include <stdio.h>
int func1(void)
{ return 500; }
int func2(void)
{ return 600; }
int func3(void)
{ return 700; }
The above code compiles in g++, but does not compile in gcc (even if you make changes related to gcc like changing the code to .c, not using any C++ header files, etc.). The error displayed is "duplicate definition of inline function - func3".
Can you clarify why this difference is present across compilers?
Also, when you run the program (g++ compiled) by creating two separate compilation units (main.o and tran.o) and create an executable a.out, the output obtained is:
500
6
700
Why does the compiler pick up the definition of the function which is not inline. Actually, since #include is used to "add" the inline definition I had expected 5,6,7 as the output. My understanding was during compilation since the inline definition is found, the function call would be "replaced" by inline function definition.
Can you please tell me in detailed steps the process of compilation and linking which would lead us to 500,6,700 output. I can only understand the output 6.
This answer is divided into the following sections:
How to reproduce the duplicate definition of inline function - func3 problem and why.
Why defintion of func3 is a duplicate instead of func1.
Why it compiles using g++
How to produce the duplicate definition of inline function - func3 problem
The problem can be successfully reproduced by
Rename tran.cpp to tran.c
Compile with gcc -o main main.c tran.c
#K71993 is actually compiling using the old gnu89 inline semantics, which is different from C99. The reason for renaming tran.cpp to tran.c is to tell the gcc driver to treat it as C source instead of C++ source.
Why definition of func3 is a duplicate instead of func1.
GNU 89 inline semantics
The following text is quoted from GCC Document: An Inline Function is As Fast As a Macro explains why func3 is a duplicate definition instead of func1, since func3 (instead of func1) is an externally visible symbol (in GNU89 inline semantics)
When an inline function is not static, then the compiler must assume that there may be calls from other source files; since a global symbol can be defined only once in any program, the function must not be defined in the other source files, so the calls therein cannot be integrated. Therefore, a non-static inline function is always compiled on its own in the usual fashion.
If you specify both inline and extern in the function definition, then the definition is used only for inlining. In no case is the function compiled on its own, not even if you refer to its address explicitly. Such an address becomes an external reference, as if you had only declared the function, and had not defined it.
C99 inline semantics
If compiled with C99 standard, i.e., gcc -o main main.c tran.c -std=c99, the linker will complain that definition of func1 is a duplicate due to the reason that extern inline in C99 is a external definition as mentioned in other posts and comments.
Please also refer to this execellent answer about semantic differents between GNU89 inline and C99 inline.
Why it compiles using g++.
When compiled with g++, the source program are considered as C++ source. Since func1, func2 and func3 are defined in multiple translation units and their definitions are different, the One Defintion Rule of C++ is violated. Since the compiler is not required to generate dignostic message when definitions spans multiple translation units, the behavior is undefined.
Maybe you should post the actual code. The snippets you show don't compile:
inline.h has extern inline int func1(void) That doesn't make any sense.
main.h has #define <stdio.h> I think you meant include instead.
Once I fixed those and compiled with gcc, it compiled fine and I got the following output
5
6
7
When I compile with g++, I get this output:
5
6
700
That happens because func3() is not static in inline.h
The compiling error is because there is a duplicate definition of func1();
Because func1() is defined using extern inline, it will produce a external definition.
However, there is also an external definition in tran.c, which cause multiple definition error.
However, func2() and func3() do not produce an external definition, hence no redefinition error.
You might want to look at here http://www.greenend.org.uk/rjk/2003/03/inline.html.
Also, take a note that c++ and c treats inline functions differently, and even in c, different standards (c89 vs. c99) treats inline functions differently.
Your code is invalid from the C++ point of view, since it blatantly violates the One Definition Rule. The only reason you managed to compile it by C++ compiler is the loose error checking in your C++ compiler (it happens to be one of those parts of ODR where "no diagnostic is required").
Your code is not valid C, because it provides duplicate external definition of function func1. Note that it is func1, not func3 that is problematic from the C point of view. There's nothing formally wrong with your func3. Your func2 is also OK, as long as the two definitions never "meet" each other in the same translation unit.
One possible reason you might be getting a different diagnostic report from your compiler is that your C compiler might be supporting inline functions in some non-standard compiler-specific way (either a pre-C99 compiler or a modern compiler run in non-standard "legacy" mode).
Frankly, I find it hard to believe you are getting an error report about func3 from any compiler, assuming the code you posted accurately represents what you are trying to compile. Most likely what you posted is not the real code.
The compile error you see is actually a linker error.
gcc and g++ are treating static inline a little differently. inline was first part of C++ and then made into an extension to many C compilers, before being added to standard C. The standard semantics could be different, but it could just be the implementations that are different.
It could also have something to do with some crazy stuff that happens with C++ code that gets rid of duplicate template stuff catching other duplicate stuff as well.
basically Inline is a late entry to GCC ( I mean c compiler).
"[ . . . ] An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition."
— ISO 9899:1999(E), the C99 standard, section 6.7.4