Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload built-in (intrinsic?) function

Consider following code:

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

double log(double) { return 42; }

int main() {
    std::cout << log(1) << std::endl;
}

While build debug version all used compilers (msvc,gcc,clang) prints 42.

But when i try build (and run) in release mode i got:

  • compilation error in msvc: error C2169: 'log' : intrinsic function, cannot be defined;
  • prints 42 for gcc;
  • prints 0 for clang.

Why release/debug results are different for same compiler?

Why got different results for different compilers in release mode?

like image 302
αλεχολυτ Avatar asked Mar 17 '23 23:03

αλεχολυτ


2 Answers

You are defining a function that is already declared in <math.h> with external linkage.

C11 standard, §7.12.6.7:

#include <math.h>
double log(double x);

§7.1.2:

Any declaration of a library function shall have external linkage.

[extern.names]/3:

Each name from the Standard C 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.

According to [reserved.names]/2 the behavior is undefined; The implementation can thus do what it wants, including the issuance of nonsensical error messages.

like image 199
Columbo Avatar answered Mar 28 '23 05:03

Columbo


So according to the standard (17.6.1.2.4):

In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).

It's unspecified whether or not the log() in math.h (really cmath) is in namespace std or not. If it is (like it is for libstdc++ for gcc), then calling log(1) quite simply calls your function because the other one is named std::log(). But for clang, apparently it puts it in the global namespace. Since there is a

template <typename T> double log(T x);

That will be preferred to yours since you're passing an int, so on clang it will call that one. (I can't check this right now since I can't access coliru and don't have clang installed, but this is a best guess).

like image 33
Barry Avatar answered Mar 28 '23 05:03

Barry