iostream为什么定义abs函数,以及如何停止它

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

本文关键字:何停止 为什么 定义 abs 函数 iostream      更新时间:2023-10-16

以下c++代码不编译:

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

当然,它抱怨abs没有定义。但以下内容确实编译了:

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

它输出两个5(而不是5.1)。这很糟糕,原因有很多。首先,abs是一个非常自然和常见的函数,所以我一直在使用它,但int部分几乎从来都不是我想要返回的。其次,对我(或使用我代码的人)来说,只写abs而不注意到它编译了但做了错误的事情太容易了,因为我(他们)真的很善于忽视警告。第三,我只是不明白为什么iostream无论如何都要麻烦定义abs函数。第四,我真的不明白为什么它会进入全局命名空间。

有什么方法可以防止这个令人反感的abs函数进入我的全局命名空间吗?

如果重要的话,我正在使用

gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.6)

很可能iostream包含stdlib.h来完成它的一些工作。这是头的C版本,它仅在全局命名空间中为int声明abs(在C中,必须为double值使用fabs)。

我不知道有什么具体的方法可以防止abs以这种方式被包含,但我知道g++4.5在不让iostreamstring等基本包含带来多余的东西方面要好得多。

也可能会得到一个警告,即double被截断为int(EDIT:yes,使用-Wconversion进行警告)。

在C中,包含一个标准标头是不允许表现得像包含任何其他标准标头一样。这避免了您所看到的问题,在实现困难方面付出了相当大的代价。

C++允许任何标准标头包括任何其他标准标头。这使得实现变得相当容易,但可能会导致您所看到的那种问题,包括一个看似不相关的标头会使您不想使用的函数可见,而不是因为您使用的函数根本没有声明而导致错误。

不幸的是,我认为没有一个简单的方法来处理这个问题。尽管很容易想象<iostream>独立于<stdlib.h>,但更容易看出它可能需要/想要ios_base之类的定义。要定义禁止前者同时允许后者的内容,需要相当多的额外工作。

然而,我应该指出,随着时间的推移,这种情况似乎确实有所改善。十年前,几乎所有的标准头球都包括其中的任何一个,这是很常见的。尽管大多数仍然包括至少一些不是严格要求的,但它们通常更接近于每个定义它所需要的。

如果这是一个正在进行的维护问题,为什么不在程序的开头添加一点代码,专门检查abs()问题?

// test if abs() is defined incorrectly, as would happen if <stdlib.h> were
// included by <iostream>.  abs() it should return a float/double, not an int
// (put suggestions here how to fix problem)
if (abs(-5.1) == 5)
{
     std::cerr << "Invalid build:  abs() defined improperly, ..." << std::endl;
     return 2;  // exit program by returning from main
}

这将使警告更难被忽视。