views:

205

answers:

6

I have two C++ files, say file1.cpp and file2.cpp as

//file1.cpp  
#include<cstdio>  
void fun(int i)  
{  
   printf("%d\n",i);  
}

//file2.cpp
void fun(double);
int main()
{
   fun(5);
}  

When I compile them and link them as c++ files, I get an error "undefined reference to fun(double)".
But when I do this as C files, I don't get error and 0 is printed instead of 5.
Please explain the reason.
Moreover I want to ask whether we need to declare a function before defining it because
I haven't declared it in file1.cpp but no error comes in compilation.

A: 
#include <stdio.h>

int Sum(int j, int f)
{
    int k;
    k = j + f;
    return k;
}
main()
{
   int i=3;
   int j = 6;

   int k = sum(i,j);

   printf("%d",k);
}

Output is 9

bachchan
I am completely lost as to what this has to do with the question.
MBennett
Your program doesn't compile, let alone answer the question.
avakar
Does you answer has any link to the question asked ?
Ashish
+5  A: 

This is because C++ allows you to overload functions and C does not. It is valid to have this in C++:

void fun(int i);
void fun(double i);
...
void fun(int i) { return 1;}
void fun(double i) { return 2.1; }

but not in C.

The reason you aren't able to compile it with your C++ compiler is because the C++ compiler sees the declaration as double and tries to find a definition for it. With the C compiler, you should be getting an error for this as well, I would think you didn't enter the code exactly as you said you did when testing this with the C compiler.

The main point: C++ has function overloading, C does not.

Tom Dignan
I compiled and linked two files with C compiler asgcc -c file1.cgcc -c file2.cgcc -o prog file2.o file1.oIt didn't show any error and result came as 0.
Happy Mittal
The C code is indeed invalid as far as the standard is concerned, however, in practice, the symbol names only contain the name of the function, not the entire signature, making the error invisible to the linker.
avakar
when you compile it with gcc, see what happens if you add these switches -Wall -Werror
Tom Dignan
It is a perfectly valid (except for the C++ comments and C++ include header) C program (meaning each compilation unit should compile). The output though is undefined as the linker can not pick up the conflict in the types. It was a common problem for C and why tools like lint were common.
Martin York
+1  A: 

C++ (a sadistic beast, you will agree) likes to mangle the names of the functions. Thus, in your header file for the C part: at the top:

#ifdef __cplusplus
extern "C" {`
#endif

at the bottom:

#ifdef __cplusplus
}
#endif

This will persuade it not to mangle some of the names. Look here

OR, in your cpp you could say

extern "C" void fun( double );
nc3b
+6  A: 

This is most likely because of function overloading. When compiling with C, the call to fun(double) is translated into a call to the assembly function _fun, which will be linked in at a later stage. The actual definition also has the assembly name _fun, even though it takes an int instead of a double, and the linker will merrily use this when fun(double) is called.

C++ on the other hand mangles the assembly names, so you'll get something like _fun@int for fun(int) and _fun@double for fun(double), in order for overloading to work. The linker will see these have different names and spurt out an error that it can't find the definition for fun(double).

For your second question it is always a good idea to declare function prototypes, generally done in a header, especially if the function is used in multiple files. There should be a warning option for missing prototypes in your compiler, gcc uses -Wmissing-prototypes. Your code would be better if set up like

// file1.hpp
#ifndef FILE1_HPP
#define FILE1_HPP
void fun(int)
#endif

// file1.c
#include "file1.hpp"
...

// file2.c
#include "file1.hpp"
int main()
{
    fun(5);
}

You'd then not have multiple conflicting prototypes in your program.

Scott Wales
But why it prints 0 instead of 5?
Happy Mittal
@Hap Because it is interpreting the bits representing 5.0 as a integer, which has an undefined result
Scott Wales
The hex representation of IEEE-754 double 5.0 would be 0x4014000000000000. If your system is little-endian like x86, reading the first four bytes of that off the stack would be 0, which is then printed.
Mark B
+1  A: 

A holdover of the C language is that it allows functions to be called without actually requiring the declaration visible within the translation -- it just assumes that the arguments of such functions are all int.

In your example, C++ allows for overloading, and does not support implicit function declarations - the compiler uses the visible function fun(double), and the linker fails because the function fun(double) is never implemented. fun(int) has a different signature (in C++), and exists as a unique symbol, whereas a C compiler (or linker, depending on visibility) would produce an error when you declare both fun(int) and fun(double) as C symbols.

That's just how languages evolved over the years (or not). Your compiler probably has a warning for this problem (implicit function declarations).

You'll see different results when you declare the functions as C functions (they're declared as C++ functions in your example when compiled as C++ source files).

C++ requires the function to be declared before it is used, C does not (unless you tell your compiler to warn you about the issue).

Justin
A: 

When compiled as C++ you are allowed to have two functions with the same name (as long as they have different parameters). In C++ name mangling is used so the linker can distinguish the two:

fun_int(int x);
fun_double(double x);

When compiled in C there is only one function with a specific name.
When you compile file1.c it generate a function that reads an integer from the stack and prints it.

When you compile file2.c it sees that the fun() takes a double. So it converts the input parameter to a double push it onto the stack then inserts a call to fun() into the code. As the function is in a different compilation unit the actual address is not resolved here but only when the linker is invoked. When the linker is invoked it sees a call to fun needs to be resolved and inserts the correct address, but it has no type information to validate the call with.

At runtime 5 is now converted into a double and pushed onto the stack. Then fun() is invoked. fun() reads an integer from the stack and then prints it. Because a double has a different layout to an integer what will be printed will be implementation defined and depends on how both double and int are layed out in memory.

Martin York