0

Why does this not return an error for duplicate function definition since the c++ standard library does external linkage.

This shouldn't be function overloading since its is type double(double,double) which is the exact same as the pow defined in math.h

#include <iostream>
#include <math.h>

double pow(double base, double exponent) {
    return 1;
}

int main() {
    std::cout << pow(2, 2);
}
  • 2
    Violation of one definition rule is an Undefined Behavior. – user7860670 Jan 13 '21 at 10:33
  • with `#include ` it prints `1` https://ideone.com/DxFDyK and with `#include ` it prints `4` https://ideone.com/RrG2nw – mch Jan 13 '21 at 10:34
  • In my version of libstdc++, there only is `long double pow(long double, long double)` and `float pow(float, float)`. Those do cause redefinition errors – perivesta Jan 13 '21 at 10:36
  • Does this answer your question? [Is it undefined behavior to redefine a standard name?](https://stackoverflow.com/questions/14770384/is-it-undefined-behavior-to-redefine-a-standard-name) or [Redefining function from standard library](https://stackoverflow.com/questions/50741722/redefining-function-from-standard-library) or etc. – underscore_d Jan 13 '21 at 10:52
  • @underscore_d i think so – Matthew Wyatt Jan 13 '21 at 11:03

2 Answers2

1

The function signature pow(double, double) is reserved to the language implementation in the global namespace. By defining a reserved name, the behaviour of the program is undefined.

Then the behaviour of the program is undefined, you are not guaranteed to be "raised an error for duplicate definition".

Related standard rules (from latest draft):

[reserved.names.general]

If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by [library], its behavior is undefined.

[extern.names]

Each name from the C standard library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.

Each function signature from the C standard library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Are you sure about the reasoning? https://stackoverflow.com/a/33856407/580083 – Daniel Langr Jan 13 '21 at 10:52
  • @DanielLangr I added some qualification. – eerorika Jan 13 '21 at 10:53
  • Even now I am not convinced that the reasoning is correct. https://stackoverflow.com/q/50925440/580083 – Daniel Langr Jan 13 '21 at 10:57
  • Thanks for the clarification. The quote in the linked answer only says that _each function signature_ is reserved. – Daniel Langr Jan 13 '21 at 11:00
  • @DanielLangr I changed to "function signature" rather than "name". – eerorika Jan 13 '21 at 11:00
  • @eerorika I assume this is for both c and c++ std library? Will this change when the c++ library is remade from modules? – Matthew Wyatt Jan 13 '21 at 11:06
  • @MatthewWyatt I doubt they would remove standard headers, so I doubt this would change any time soon. Maybe after they've been deprecated for some time, if they choose to do so at all - but I doubt it since C compatibility is something that is still cared for. – eerorika Jan 13 '21 at 11:07
  • @eerorika is it for both c and c++ libraries? also if they remade std lib with modules they would use new names to maintain compatibility – Matthew Wyatt Jan 13 '21 at 11:10
0

Why does this not return an error for duplicate function definition...?

Because the definition of pow provided by the C library does not need to be in the included header file. This header file (math.h) may include only its declaration. In such a case the resulting translation unit may look like:

...
double pow(double, double);
...

double pow(double base, double exponent)
{
    return 1;
}

int main()
{
    std::cout << pow(2, 2);
}

There is absolutely nothing wrong with this translation unit. But, the problem occurs during linking, since a linker can link your pow call to two different functions at a machine-code level — the one provided by the C library and the other provided by the object file created from the translation unit.

What the linker will actually do is not defined by the C++ Standard. It simply says only that the behavior for your code is undefined.

Daniel Langr
  • 22,196
  • 3
  • 50
  • 93
  • While the reserved names section says that behaviour is undefined, as I cover in my answer, if we ignore that then the ODR rule says that the program is ill-formed (no diagnostic required). Not that there is practical difference between UB and IFNDR as far as I can tell. – eerorika Jan 13 '21 at 11:04
  • @eerorika I agree. I just tried to explain how a compiler may treat this code in practice. – Daniel Langr Jan 13 '21 at 11:09