Why is the mismatch between declaration and definition not raising error during compilation?

102 Views Asked by At

I have two source files, main.cpp and math.cpp, along with a header file math.h. The code is as follows:

// main.cpp
#include "math.h"
#include <iostream>
int main()
{
    std::cout << add(5, 10);
    return 0;
}


// math.cpp
#include "math.h"
int add(int x)
{
    return x;
}


// math.h
int add(int x, int y);

I have intentionally created a mismatch between the declaration and definition of add.

Since I have included math.h in math.cpp, I expect the compiler to raise an error when I run the command clang++ main.cpp math.cpp -c. Instead, the compilation succeeds.

I understand that the mismatch will eventually cause an error at link-time but can someone explain why the compilation is succeeding in this case?

4

There are 4 best solutions below

0
Pete Becker On BEST ANSWER

This code is legal:

#include <iostream>

int add(int);
int add(int a, int b) {
    return a + b;
}

int add(int x) {
    return x + 1;
}

int main() {
    std::cout << add(1, 2) << '\n'; // calls two-argument version
    std::cout << add(3) << '\n';    // calls one-argument version
    return 0;
}

It's simply function overloading. If the single-argument version isn't used it doesn't have to be defined:

#include <iostream>

int add(int);
int add(int a, int b) {
    return a + b;
}

// int add(int x) {
//     return x + 1;
// }

int main() {
    std::cout << add(1, 2) << '\n'; // calls two-argument version
    // std::cout << add(3) << '\n';    // calls one-argument version
    return 0;
}

Putting the declaration of int add(int) into a header doesn't change the meaning of the code.

0
463035818_is_not_an_ai On

You can have a second source file

// math2.cpp
#include "math.h"
int add(int x,int y)
{
    return x;
}

or not. The compiler does not know (nor care) while compiling math.cpp.

Since I have included math.h in math.cpp, I expect the compiler to raise an error when [...]

When you compile math.cpp then the declaration does not match the definition, but there is no reason to complain about it. math.h could declare a void foo() and math.ccp could define a void bar() and there would also be no reason for the compiler to complain about that.

0
Jabberwocky On

In math.cpp you implement int add(int x) which happens to be different from int add(int x,int y) defined in math.h. From your point of view, that may be wrong, but from the C++ point of view this is correct, because C++ allows function overloading.

Now in main.cpp you use add(5, 10). For the compiler this is OK because in math.h you define int add(int x,int y), which basically tells the compiler "there is a function int add(int x,int y) implemented somewhere", so there is no problem for compiling.

Finally at link time the linker needs to generate the code that actually calls int add(int x, int y) but there is no such function and therefore it complains.


The compiler doesn't care if you compile both files together or separately.

This:

$ clang++ main.cpp math.cpp -c

is exactly equivalent to this:

$ clang++ main.cpp -c
$ clang++ math.cpp -c
0
Vlad from Moscow On

Within main.cpp

// main.cpp
#include "math.h"
#include <iostream>
int main()
{
    std::cout << add(5, 10);
    return 0;
}

the included header math.h declares the function add with two parameters

// math.h
int add(int x, int y);

Thus this statement where the function is called

    std::cout << add(5, 10);

is correct.

The name add is declared with the required number of parameters.

Within math.cpp there are declared two overloaded functions

// math.cpp
#include "math.h"
int add(int x)
{
    return x;
}

namely

int add(int x, int y);

and

int add(int x)
{
    return x;
}

One of the funtions is also defined. So the compilation unit is correct. There is nothing wrong. An error can occur at phase of the linkage.