Can a declaration affect the std namespace? - c++

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

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.

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

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.

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.

Overload resolution with extern "C" linkage

In a mixed C/C++ project, we need to make a call from C to a C++ function. The function to be called is overloaded as three separate functions, but we can ignore that from the C-side, we just pick the one most suitable and stick to that one.
There's two ways to do this: (1) write a small C++ wrapper with a extern "C" function that forwards the call to the chosen overloaded function, or (2) the hackish way to just declare the one function we want to call from C as extern "C".
The question is, is there any disadvantages (apart from nightmares and bad karma) to go for the second variant? In other words, given three overloaded function, where one is declared as exern "C", should we expect trouble with the C++ side, or is this well defined according to the standard?
I believe the language in the standard is specifically written to allow exactly one function with "C" linkage, and an arbitrary number of other functions with "C++" linkage that overload the same name (§[dcl.link]/6):
At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function. Two declarations for an object with C language linkage with the same name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same object.
The standard shows the following example:
complex sqrt(complex); // C + + linkage by default
extern "C" {
double sqrt(double); // C linkage
}
Even if it was allowed by the standard, future maintainers of the code will probably be extremely confused and might even remove the extern "C", breaking the C code (possibly far enough later that the events aren't linkable).
Just write the wrapper.
EDIT:
From C++03 7.5/5:
If two declarations of the same
function or object specify different
linkage specifications (that is, the
linkage specifications of these
declarations specify different
string literals), the program is
ill-formed if the declarations appear
in the same translation unit, and the
one definition rule (3.2) applies if
the declarations appear in different
translation units...
I interpret this to not apply since C and C++ functions with the same name aren't actually the same function but this interpretation may be wrong.
Then from C++03 7.5/6:
At most one function with a particular
name can have C language linkage...
This then implies that you could have other, non-C-linkage, functions with the same name. In this case, C++ overloads.
As long as you follow the other rules for extern-C functions (such as their special name requirements), specifying one of the overloads as extern-C is fine according to the standard. If you happen to use function pointers to these functions, be aware that language linkage is part of the function type, and needing a function pointer to this function may decide the issue for you.
Otherwise, I don't see any significant disadvantages. Even the potential disadvantage of copying parameters and return value can be mitigated by compiler- and implementation-specifics that allow you to inline the function – if that is determined to be a problem.
namespace your_project { // You do use one, right? :)
void f(int x);
void f(char x);
void f(other_overloads x);
}
extern "C"
void f(int x) {
your_project::f(x);
}
(This answer applies to C++14; other answers so far are C++03).
It is permitted to use overloading. If there is an extern "C" function definition of some particular name then the following conditions apply (references to C++14 in brackets):
The declaration of the extern "C" function must be visible at the point of any declaration or definition of overloads of that function name (7.5/5)
There must be no other extern "C" definition of a function or variable with the same name, anywhere. (7.5/6)
An overloaded function with the same name must not be declared at global scope. (7.5/6)
Within the same namespace as the extern "C" function, there must not be another function declaration with the same name and parameter list. (7.5/5)
If any violation of the above rules occurs in the same translation unit the compiler must diagnose it; otherwise it is undefined behaviour with no diagnostic required.
So your header file might look something like:
namespace foo
{
extern "C" void bar();
void bar(int);
void bar(std::string);
}
The last bullet point says that you cannot overload solely on linkage; this is ill-formed:
namespace foo
{
extern "C" void bar();
void bar(); // error
}
However you can do this at different namespaces:
extern "C" void bar();
namespace foo
{
void bar();
}
in which case , normal rules of unqualified lookup determine whether a call bar() in some code finds ::bar, foo::bar, or ambiguous.