Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/articles/c-tutorials/)
-   -   GCC:: Calling Function With Same Name But Different Return Type (http://www.go4expert.com/articles/gcc-calling-function-return-type-t27172/)

poornaMoksha 17Nov2011 23:18

GCC:: Calling Function With Same Name But Different Return Type
 
After writing Why main() should not have void as return type? article the other day, suddenly one more question came up into my mind about the signature of main() function. In the earlier article I discussed about why 'void main()' should not be used when ANSI C expects the function main() to return an integer. But, how it is possible that main() is declared to return and integer while we can define it with return type as void. Sounds like a valid question, isn't it?

How I went about finding the answer



It was not a very easy task to start with as I needed to have a look at the code that calls the main() function. Well, since that was a bit difficult so I first thought of an easy way around. I used the following code :

Code:

#include<stdio.h>
 
int func();
 
int main(void)
{
    int ret = func();
    printf("\n Executed!!! with ret[%d] \n", ret);
    return ret;
}
 
void func()
{
    printf("\n Inside func()\n");
}

In the above code, I have declared a function 'func' with 'int' as return type but defined it with 'void' return type.

Now, when I compiled the code, I got :

Code:

~/practice $ gcc -Wall typemismatch.c -o typemismatch
typemismatch.c:12: error: conflicting types for ‘func’
typemismatch.c:3: note: previous declaration of ‘func’ was here

I got an error saying that the declaration and definition have conflict and as I knew, conflict was in the return types. Well, this was expected but then how come we do not get error for defining main() with void return type? The question was still lingering around.

The question kept me quite for some time until I realized that through above example, I could not quite simulate what exactly happens with main() function. Then I re-structured the above example into :

Code:

// test.c
#ifndef TEST_H_INCLUDED
#include"test.h"
#endif
 
extern int func();
 
int main(void)
{
    int ret = func();
    printf("\n Executed!!! with ret[%d] \n", ret);
    return ret;
}

Code:

//test1.c
#ifndef TEST_H_INCLUDED
#include"test.h"
#endif
 
void func()
{
    printf("\n Inside func()\n");
}

Code:

//test.h
#define TEST_H_INCLUDED
#include<stdio.h>

Well, reason for restructuring was :

Since, main was declared/called from a separate file and defined in a separate file so I had to re structure my example so that the function func() was declared/called from test.c but it is defined in test1.c (see code snippets above).

Now, since I re-structured the code in the way I wanted, I went ahead with the compilation process :

Code:

gcc -Wall test.c test1.c -o test
the compilation went fine. Now when i executed, I got :

Code:

~/practice $ ./test
 
 Inside func()
 
 Executed!!! with ret[16]

Well, this was like a hot blow. How gcc compiled and executable ran fine for a code that contains conflicting declarations and definitions of a function?

And to add on to the confusion : when I put the definition of func() in the same file from where it is being called(refer very first example) and remove the extern keyword from the declaration then I get compilation error. So if I see from a no error situation to an error situation only two things changed :
  1. Removed 'extern'
  2. Put the definition in the same file which contains declaration
I was not able to conclude which of the above two changes are causing the impact and how?

Then out of curiosity I did one more test, I changed test1.c to :

Code:

#ifndef TEST_H_INCLUDED
#include"test.h"
#endif
 
void func(int a)
{
    printf("\n Inside func()\n");
}

ie, I defined the function func() so that it accepts an integer argument and now I again compiled and ran the executable and to my damn surprise, func() was called smoothly. Neither compiler complained, nor linker complained, no run time issues.

What the hell is happening? I had never seen something like this before in C or to be more precise I have never observed such behavior so closely. Anyways now situation became interesting. I consulted my colleagues in office about this behavior the very next day. Some answered that error should have been thrown by the compiler, some said that behavior could be undefined in this case while rest of them were also left confused over the issue.

Then I searched on INTERNET a bit and found my answers in pieces, I tried to collect some important pieces of explanation and here it is :
  • If the function with different return type is defined in the same file so gets compiled as a single compilation unit.
  • So compiler has visibility of the contradictory return types and hence it gives errors.
  • When the definition is in some other file then two files get compiled as two separate compilation units.
  • Since we declare the function with 'extern' keyword so it is enough to satisfy the compiler that the definition of the function is definitely there but not in this file. So, compiler does not spit errors while creating a .o file.
  • Similarly the file in which definition is there gets compiled into a .o file without any problem.
  • Now comes the linking stage where in the linker has to see that the symbol 'func' which is called in test.c should have a matching definition.
  • So it looks for symbol 'func' in test1.c and finds it there.
  • Since compiler did its work earlier and linker has to just satisfy the linking dependencies so nobody takes care of the fact that whether the function call is being linked with a function of same signature or not. All that is needed is that the name of the function should be same.
Ohh...damn...this is something weird.

Ya, this was my reaction after understanding all the points above. I assume the same must be the reason for my original question regarding conflict of return types in main() function.

Now, one more thing came into my mind, If this is so, then If I define one more function with same name(func) in yet another separate file test2.c and compile it with test.c and test1.c then what will happen?

Below is the complete code :

Code:

// test.c
#ifndef TEST_H_INCLUDED
#include"test.h"
#endif
 
extern int func();
 
int main(void)
{
    int ret = func();
    printf("\n Executed!!! with ret[%d] \n", ret);
    return ret;
}

Code:

//test1.c
#ifndef TEST_H_INCLUDED
#include"test.h"
#endif
 
void func()
{
    printf("\n Inside func()\n");
}

Code:

//test2.c
#ifndef TEST_H_INCLUDED
#include"test.h"
#endif
 
int func(int a)
{
    printf("\n Inside func() 2\n");
    return 0;
}

Code:

//test.h
#define TEST_H_INCLUDED
#include<stdio.h>

This is what I got when I compiled the above piece :

Code:

~/practice $ gcc -Wall test.c test1.c test2.c -o test
/tmp/ccOlT5KP.o: In function `func':
test2.c:(.text+0x0): multiple definition of `func'
/tmp/ccwYpras.o:test1.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status

Which confirmed that C compiler just works on function names or rather symbols. Since it finds two function definitions with same name, so Linker at this point is helpless and hence throws errors stating that :

" I found two definitions and I don't know which one to link to?"

This also cleared one more fact that is C does not support function overloading.

The gcc version that I used for all the above tests is :

Quote:

gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)
Thats all for today folks!!!

Conclusion



To Conclude, the above article is a bit of research that I did when I found a weird problem of C compiler/Linker not being able to identify the conflict in declaration and definition signatures when these are kept in different files.

Stay tuned for more!!!!!

wdliming 16Dec2011 10:11

Re: GCC:: Calling Function With Same Name But Different Return Type
 
Oh it's a good issue,I have learned a lot !~~Thank you for your sharing!


All times are GMT +5.5. The time now is 03:09.