GCC:: Calling Function With Same Name But Different Return Type

Discussion in 'C' started by poornaMoksha, Nov 17, 2011.

  1. poornaMoksha

    poornaMoksha New Member

    Joined:
    Jan 29, 2011
    Messages:
    150
    Likes Received:
    33
    Trophy Points:
    0
    Occupation:
    Software developer
    Location:
    India
    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 :

    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!!!!!
     
  2. wdliming

    wdliming New Member

    Joined:
    Sep 26, 2010
    Messages:
    28
    Likes Received:
    0
    Trophy Points:
    0
    Oh it's a good issue,I have learned a lot !~~Thank you for your sharing!
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice