1
#include <cmath>
int abs;
int main()
{

}

This code throws the compilation error

error: 'int abs' redeclared as different kind of symbol
note: previous declaration 'int abs(int)'

The same thing happens if I include it from cstdlib.

I read this documentation https://en.cppreference.com/w/cpp/numeric/math/abs where it is nowhere mentioned that abs would be defined outside std. In fact, it explicity mentions it as std::abs everywhere.

The same thing happens with other functions, such as sqrt.

Why is this happening? How can I use these functions without cluttering my namespace? If not possible, are there c++ alternatives?

GT 77
  • 448
  • 5
  • 12
  • 3
    Before C++, there was C. – Sam Varshavchik May 17 '21 at 15:16
  • 2
    This question seems different from the linked duplicate. Or I don't see which answer in the duplicate answers this question. – François Andrieux May 17 '21 at 15:21
  • 3
    c++ implementations must have `std::abs` there's nothing stopping them from having `abs` declared in the global namespace too – Alan Birtles May 17 '21 at 15:21
  • @AlanBirtles Is a conforming implementation actually allowed to define any symbol it wants in the global namespace? I would have thought they were at least restricted to using reserved symbols. – François Andrieux May 17 '21 at 15:23
  • The C++ headers, like ``, are allowed to pull in more identifiers than just the mandated ones. Effectively, it may cause some global namespace pollution (as you ran into), and even `std` namespace pollution (because of pulling in other C++ headers, indirectly). The global namespace is the *wild, wild west*. – Eljay May 17 '21 at 15:23
  • 1
    The standard requires these to be accessible in the namespace `std`, but does not require them to not be added to the global namespace. – molbdnilo May 17 '21 at 15:25
  • @FrançoisAndrieux I also believe [the listed duplicate](https://stackoverflow.com/questions/13889467/should-i-include-xxxx-h-or-cxxxx-in-c-programs) is not quite correct. The proper header is being included here. Reopening. – Drew Dormann May 17 '21 at 15:29
  • 1
    @FrançoisAndrieux -- the rule is that the `` headers are **required** to declare all of the corresponding C functions inside the namespace `std` and are **allowed** to also put them in the global namespace. Same thing, in reverse, for the `` headers: they are **required** to put the names in the global namespace, and are **allowed** to also put the names in the `std` namespace. – Pete Becker May 17 '21 at 15:29
  • @molbdnilo: Is it only function names that get mangled in C++ implementations? In C++, if one were to define `double abs(double *p)` such a definition wouldn't create a linker conflict with anything else called `abs`. – supercat May 17 '21 at 15:30
  • @supercat -- name mangling is an implementation detail. It is not the root of this issue. Back in C++98, the `` headers were not allowed to put the C names into the global namespace. This was unimplementable on some platforms, so implementations are now allowed to also put the names into the global namespace. – Pete Becker May 17 '21 at 15:31
  • @PeteBecker: The Standard makes clear that implementations must *somehow* allow "double abs(double *p)" and "int abs(intvalue)" to be treated as distinct symbols. Whether they accomplish this by adding printable characters to the symbols, or via other means, is an implementation detail, but semantically those two symbols have different names. If symbols not declared `extern "C"` were all given names distinct from those that were declared in such fashion, I don't see any reason implementations would need to pollute the global namespace of the former symbols unless... – supercat May 17 '21 at 16:00
  • ...configured for ABI compatibility with compilation units processed by other implementations. Since the C++ Standard doesn't contemplate cross-implementation linking, a conforming implementation could specify that cross-implementation linking is only available in a non-conforming mode. – supercat May 17 '21 at 16:01
  • @supercat — library implementors asked for that change. If you have to host a C++ library implementation on top of a C standard library that you don’t control, keeping the C names out of the global namespace is, at best, brittle. The change was made to match actual practice. – Pete Becker May 17 '21 at 18:44
  • @PeteBecker: A major defect in both the C and C++ Standards is that the authors don't have any consensus understanding of the Standards' jurisdiction, especially with regard to constructs that may not be supportable on some obscure systems, but that commonplace implementations should nonetheless process consistently. – supercat May 17 '21 at 19:16
  • @PeteBecker: If one were to poll all of the Committee members with questions such as "Is the Standard intended to fully describe, or mandate that implementations document, everything necessary to make an implementation suitable for any particular purpose(s)? If so, what purpose(s)?" do you think the Committee members would give consistent answers? – supercat May 17 '21 at 19:53
  • @PeteBecker: Unlike e.g. Linus Torvalds, I don't accuse Committee members of being stupid, but I instead believe that different members have conflicting priorities that have for decades made it impossible for them to reach consensus on some important issues. If some members of the Committee are unwilling to budge on each of three key issues, and satisfying any two of them perfectly would make the third impossible, such a conflict will make it impossible to fix many long-standing defects. Conversely, if the Committee could reach and articulate a consensus on how to balance... – supercat May 17 '21 at 20:28
  • ...the three key issues, the solutions to many defects would become obvious. – supercat May 17 '21 at 20:29

1 Answers1

7

Why is abs not in std?

Your question is slightly wrong. abs is in std. Let me assume that you're asking "Why is abs also in the global namespace?".

The C++ standard allows the C standard functions to be declared in the global namespace in addition to being declared in the std namespace.

Why is this happening?

Because those functions are from the C standard library, and because standard allows it to happen, and because of the way your standard library was implemented.

How can I use these functions without cluttering my namespace?

Those names are reserved to the language implementation in the global namespace. There's no way to avoid it.

Don't treat the global namespace as "your namespace". The global namespace is cluttered, and it always will be. You need to work around that.

If not possible, are there c++ alternatives?

The C++ alternative is to declare your abs in your namespace:

namespace my_very_own_namespace {
    int abs;
}

You should declare everything1 in your own namespace, except:

  • That namespace itself
  • main
  • Template specialisations of names in other namespaces where that is allowed
  • Cross-language API's i.e. anything extern "C"

The hardest part is figuring out a unique name for your own namespace, since it mustn't be one that is already used by the C standard library, nor preferably any name used by other libraries in the global namespace.

1 Following this rule of thumb is hardly necessary when writing tiny exercise programs etc. But it becomes essential when writing large programs and relying on third party libraries, not to mention when writing those libraries for others to use.


Standard quotes:

[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,171 or as a name of namespace scope in the global namespace.

[headers]

Except as noted in [library] through [thread] and [depr], the contents of each header cname is the same as that of the corresponding header name.h as specified in the C standard library. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope of the namespace std. It is unspecified whether these names (including any overloads added in [support] through [thread] and [depr]) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations ([namespace.udecl]).

eerorika
  • 232,697
  • 12
  • 197
  • 326