Overload built-in (intrinsic?) function - c++

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?

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.

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).

Related

standard library not raising error for duplicate definition [duplicate]

This question already has answers here:
Is it undefined behavior to redefine a standard name?
(3 answers)
Closed 2 years ago.
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);
}
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.
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.

Can a declaration affect the std namespace?

#include <iostream>
#include <cmath>
/* Intentionally incorrect abs() which seems to override std::abs() */
int abs(int a) {
return a > 0? -a : a;
}
int main() {
int a = abs(-5);
int b = std::abs(-5);
std::cout<< a << std::endl << b << std::endl;
return 0;
}
I expected that the output will be -5and 5, but the output is the -5 and -5.
I wonder why this case will happen?
Does it have anything to do with the use of std or what?
The language specification allows implementations to implement <cmath> by declaring (and defining) the standard functions in global namespace and then bringing them into namespace std by means of using-declarations. It is unspecified whether this approach is used
20.5.1.2 Headers
4 [...] In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (6.3.6) of the namespace std. It is unspecified whether these names (including any overloads
added in Clauses 21 through 33 and Annex D) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (10.3.3).
Apparently, you are dealing with one of implementations that decided to follow this approach (e.g. GCC). I.e. your implementation provides ::abs, while std::abs simply "refers" to ::abs.
One question that remains in this case is why in addition to the standard ::abs you were able to declare your own ::abs, i.e. why there's no multiple definition error. This might be caused by another feature provided by some implementations (e.g. GCC): they declare standard functions as so called weak symbols, thus allowing you to "replace" them with your own definitions.
These two factors together create the effect you observe: weak-symbol replacement of ::abs also results in replacement of std::abs. How well this agrees with the language standard is a different story... In any case, don't rely on this behavior - it is not guaranteed by the language.
In GCC this behavior can be reproduced by the following minimalistic example. One source file
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
Another source file
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
In this case you will also observe that the new definition of ::foo ("Goodbye!") in the second source file also affects the behavior of N::foo. Both calls will output "Goodbye!". And if you remove the definition of ::foo from the second source file, both calls will dispatch to the "original" definition of ::foo and output "Hello!".
The permission given by the above 20.5.1.2/4 is there to simplify implementation of <cmath>. Implementations are allowed to simply include C-style <math.h>, then redeclare the functions in std and add some C++-specific additions and tweaks. If the above explanation properly describes the inner mechanics of the issue, then a major part of it depends on replaceability of weak symbols for C-style versions of the functions.
Note that if we simply globally replace int with double in the above program, the code (under GCC) will behave "as expected" - it will output -5 5. This happens because C standard library does not have abs(double) function. By declaring our own abs(double), we do not replace anything.
But if after switching from int with double we also switch from abs to fabs, the original weird behavior will reappear in its full glory (output -5 -5).
This is consistent with the above explanation.
Your code causes undefined behaviour.
C++17 [extern.names]/4:
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.
So you cannot make a function with the same prototype as the Standard C library function int abs(int);. Regardless of which headers you actually include or whether those headers also put C library names into the global namespace.
However, it would be allowed to overload abs if you provide different parameter types.

porting isnan to c++11

When I'm switching the compiler version from gcc 4.6 to gcc 4.8 I get the following error
error: call of overloaded 'isnan(double)' is ambiguous.
This is because in c++11 there are differend function declarations:
C: int isnan(double)
C++11: bool isnan(double)
from cpluplus:
In C, this is implemented as a macro that returns an int value. The type of x shall be float, double or long double.
In C++, it is implemented with function overloads for each floating-point type, each returning a bool value.
How can I fix this?
Although you can mitigate this problem by not saying using namespace std; everywhere, you can avoid it by being explicit about using std::isnan:
#include <cmath>
#include <iostream>
int main()
{
double x = ....;
std::cout << std::boolalpha;
std::cout << std::isnan(x) << std::endl;
}
In C++11 there should not be ambiguity between the C and C++ isnan function. It works as expected, even with using namespace std.
Please check that you are not doing both #include <math.h> and #include <cmath>. Only include cmath.
Alternatively, perhaps you somewhere have in your project a user-defined isnan(double) function, or some header includes "math.h".
Also please note, that if one wants to write generic code, it is incorrect to use the 'std::' prefix on the math functions as it breaks the argument dependent lookup (ADL). (Because the C++ standard does not allow injecting functions in the std:: namespace)
The correct use for isnan in generic code is using std::isnan; then use just isnan on the variables. Otherwise your code with user defined floating point types such as for arbitrary precision, automatic differentiation and such wont work. The root of this inconsistency is that the built in types such as double do not reside in the namespace std but the functions that operate on them do.

Inconsistent namespace injection for C library facilities headers

I was playing with ptrdiff_t and reading the C++11 standard when I came across this "issue". First, the facts:
The type ptrdiff_t (just an example) is pulled from the Standard C library header <stddef.h> into <cstddef> (§18.2/2). Section 17.6.1.2 tells us that declarations pulled from the C standard library will be within the std namespace:
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).
As it also says, the declarations may have been declared in global namespace first and then injected into std. So it would make sense, for my implementation, that the following compiles just fine:
#include <cstddef>
int main(int argc, const char* argv[])
{
std::ptrdiff_t x;
ptrdiff_t y;
return 0;
}
My implementation (gcc 4.6.3) must have declared ptrdiff_t in the global namespace and then injected it into std. However, if I compile the following code, I get an error (notice the <iostream> include):
#include <iostream>
int main(int argc, const char* argv[])
{
std::ptrdiff_t x;
ptrdiff_t y;
return 0;
}
main.cpp: In function ‘int main(int, const char**)’:
main.cpp:6:3: error: ‘ptrdiff_t’ was not declared in this scope
main.cpp:6:3: note: suggested alternatives:
/usr/include/c++/4.6/i686-linux-gnu/./bits/c++config.h:156:28: note: ‘std::ptrdiff_t’
So, since std::ptrdiff_t is available, <iostream> must be including <cstddef> in some way (although it's not required to). But why is the global version not also available as it
was before? Can I not expect this injection to be consistent even when it's actually the same header? This seems like odd behaviour. Whether the injection occurs may be unspecified, but it should at least be either one way or the other, not both, right?
Do not rely on one header including another, if you want something declared/defined in a specific header then you must include it.
For the example you gave, with g++ there are actually two definitions of ptrdiff_t (and size_t for that matter). The first, in namespace std, that comes from <bits/c++config.h>. And the one in the global namespace from <stddef.h> (and so <cstddef>).
The problem is that you did not using the correct header. You should do
#include <cstddef>
instead. However you use
#include<iostream>
And that has a definition of "std::ptrdiff_t" in it indirectly. However, the global "::ptrdiff_t" is not defined in "iostream" and "iostream" did not include "cstddef" as you thought. Instead, "iostream" does include "bits/c++config.h". The actual "std::ptrdiff_t" is defined in that file.
If you look at the content of the file "cstddef" you will find that is is only two "useful" lines there
BTW, the above discussion is for GCC 4.6 and GCC 4.7. For GCC 4.4, "iostream" indrectly include "cstddef" therefore ptrdiff_t will be available in both namespaces (std and global).
#include
#include
The latter line brings in the global "::ptrdiff_t" and the former defines the std namespace one.

Can types in `cname` and `name.h` be different types?

Is this code standard conforming?
#include <stdio.h>
#include <cstdio>
int main() {
FILE *f1 = 0;
std::FILE *f2 = f1;
}
Explanation: The standard says [headers]:
[...] the contents of each header cname shall be the same as that of the corresponding header name.h [...] as if by inclusion. In the C++ standard library, however, the declarations [...] 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).
So in case they aren't injected by explicit using-declaration, may they be different type? I don't think the "as if by inclusion" phrase is conclusive since the other half of the text clearly contradicts this requirement, requiring the names are within the std namespace.
Yes, that's standard conforming: FILE* is declared in stdio.h, std::FILE* in cstdio, and the two are the same because of the paragraph you cited.
(The only thing that's unspecified is whether, if you only include <cstdio>, you also have the same FILE* in the global namespace or not.)
Update: I believe that the types are actually the same on the nose, and that each type is declared only once and then injected in to the other namespace via a using declaration. The only thing that's unspecified is which one comes first. The corresponding opposite standard quote is D.5(2):
Every C header, each of which has a name of the form name.h, behaves as if each name placed in the standard library namespace by the corresponding cname header is placed within the global namespace scope. It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace std and are then injected into the global namespace scope by explicit using-declarations (7.3.3).
Basically, that means that two implementations are possible:
"C came first":
// foo.h
struct Gizmo { /* ... */ };
// cfoo
#include "foo.h"
namespace std { using ::Gizmo; }
"C++ with C-compatibility:
// cfoo
namespace std
{
struct Gizmo { /* ... */ };
}
// foo.h
#include <cfoo>
using std::Gizmo;
I don't believe that paragraph says that they have to be identical. It is just a revision of the original (C++98) paragraph which said:
Every C header, each of which has a name of the form name.h behaves as if each name placed in the Standard library namespace by the corresponding cname header is also placed within the namespace scope of namespace std and is followed by an explicit using-declaration (7.3.3)
This was between hard and impossible to follow, because it conflicted with the existing real C headers on most systems. So, in C++11 the text was changed to the one you quote. It allows implementations to it the other way round, like they in practice have done all along - use existing system provided C headers and import the names to namespace std.
However, there is another paragraph saying that whichever way the implementation does this, the names in the headers must mean the same thing:
For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T. ([extern.types], 17.6.4.3.4)
Yes, they can be different types. Use the C++ types; the C headers are only there for compatibility.
Consider if as the comment to the answer above suggests, the C++ header were implemented as namespace std { #include "stdio.h" }; then ::FILE and std::FILE would represent different types.