Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does iostream define an abs function, and how can I stop it?

Tags:

c++

gcc

The following c++ code does not compile:

int main() {
  double a = abs(5.1);
  return 0;
}

It complains that abs is not defined, of course. But the following does compile:

#include <iostream>

int main() {
  std::cout << abs(5.1) << std::endl;
  std::cout << abs(-5.1) << std::endl;
  return 0;
}

It outputs two 5's (not 5.1's). This is bad for lots of reasons. First, abs is such a natural and common function that I use it all the time, but the int part is almost never what I want returned. Second, it's much too easy for me (or people using my code) to just write abs and not notice that it compiles but does the wrong thing, because I'm (they're) really good at overlooking warnings. Third, I just plain don't understand why iostream bothers defining an abs function anyway. Fourth, I really don't understand why it goes into the global namespace.

Is there any way I can prevent this objectionable abs function from going into my global namespace?

If it matters, I'm using

gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.6)
like image 959
Mike Avatar asked Mar 15 '12 17:03

Mike


People also ask

Where is abs defined in C++?

The abs() function in C++ returns the absolute value of the argument. It is defined in the cmath header file. Mathematically, abs(num) = |num| .

How do you do abs value in C++?

The abs() in C++ returns the absolute value of an integer number. If the number is negative, it will return the positive value (with the same magnitude), for example, abs(-1) = 1. If the number is already positive or zero, it will return the number as it is, for example, abs(1) = 1.

Does abs work for float C++?

Special behavior for C++: For C++ applications, abs() is also overloaded for the types long, float, and long double.

What does std :: abs do?

std::abs(float), std::fabs, std::fabsf, std::fabsl. 1-8) Computes the absolute value of a floating point value arg .


2 Answers

In C, including one standard header was not allowed to act like it included any other standard header. This avoided the problem you're seeing, at considerable expense in difficulty implementation.

C++ allows any standard header to include any other standard header. This makes implementation considerably easier, but can lead to exactly the sort of problem you're seeing, where including a seemingly-unrelated header has made a function visible that you didn't really want to use, instead of getting an error because the function you used isn't declared at all.

Unfortunately, I don't think there's an easy way to deal with this. Although it's pretty easy to imagine <iostream> being independent of <stdlib.h>, it's much easier to see how it might need/want definitions of things like ios_base. It would take quite a bit of extra work to define things to prohibit the former while allowing the latter.

I should mention, however, that over time this situation does seem to be improving quite a bit. Ten years ago, it was fairly common to get virtually all standard headers from including almost any one of them. Although most still include at least a few that aren't strictly required, they're generally much closer to each defining only what it's required to.

like image 192
Jerry Coffin Avatar answered Nov 15 '22 16:11

Jerry Coffin


Most likely iostream includes stdlib.h to do some of its work. This is the C version of the header which declares abs for int only in the global namespace (in C you had to use fabs for double values).

I'm not aware of any specific way to keep abs from being included that way but I do know that g++ 4.5 is much better at not having excess stuff brought in by basic includes like iostream and string.

It may also be possible to get a warning that the double is being truncated to int (EDIT: yes, use -Wconversion to warn).

like image 42
Mark B Avatar answered Nov 15 '22 14:11

Mark B