A large number of C++ functions in the standard library are extended from standard C functions, such as qsort() , memcpy() , etc. Among these functions, many have overloaded their C counterparts. For example, abs() in C++ is overloaded for both integral and floating-point types, while it is only defined for int in C. These functions, however, are often unwittingly misused as global functions and produce unexpected results.

Functions in the C++ standard library are usually put in the namespace std , including those that are extended from their C counterparts. For example, the C function sqrt() corresponds to std::sqrt() in C++. The following function my_sqrt_1 computes the square root of the input parameter x :

#include <cmath> float my_sqrt_1(float x) { return std::sqrt(x); }

However, from time to time, people miss the std:: prefix, thinking that it is too redundant. Therefore, the above code snippet is often shortened as (using the “global version” of sqrt() )

#include <cmath> // no "using namespace std;" float my_sqrt_2(float x) { return sqrt(x); }

While it may seem to be a nice trick, it may not behave as expected. In C++, the behavior of calling a standard function without explicitly using the namespace std is implementation-dependent: A compiler may interpret the function as either the C++ function or its C counterpart. In the above example, my_sqrt_2 may possibly either

call float std::sqrt(float) with x as input and return its returned value (this is the case for x64 msvc v19.22 as tested on the C Compiler Explorer, or

with as input and return its returned value (this is the case for x64 msvc v19.22 as tested on the C Compiler Explorer, or cast x to double type, feed it into double sqrt(double) , cast the returned value back to double and return it (this is the case for x86-64 gcc 9.2 and x86-64 clang 9.0.0 on the C Compiler Explorer.

The second case may occur because the compiler has interpreted sqrt() as the C function sqrt() , which is only defined for double . If the newly defined function is repeatedly called, this may cause significant drawback in performance. What is worse, sometimes it can even cause incorrect results. Consider the following function:

#include <cmath> long double my_sqrt_3(long double x) { return sqrt(x); }

If sqrt() is interpreted as the C sqrt() function, on a CPU chip that supports long double type that is more precise than double , this function is likely to cause precision loss every time it is called, and can even output ridiculous results when x is sufficiently large. On a recent x86_64 CPU, using gcc 8.3, the following code snippet

#include <iostream> int main() { std::cout << my_sqrt_3(1e310L) << ' ' << std::sqrt(1e310L) << std::endl; return 0; }

outputs

inf 1e+155

The square root of a finite number is infinity! This is because x is first implicitly cast to double in my_sqrt_3 , which is not precise enough to store a number as large as 1e310 and therefore converted to inf .

Conclusion: Do not use the “global version” of standard C++ functions; always use the one in the std namespace.