web-dev-qa-db-ja.com

abs vs std :: abs、リファレンスは何と言っていますか?

注意してください、私は::abs()ではなくstd::abs()について話している

cplusplus.com Webサイト によると、stdlib.を含めると、abs<cmath>hCバージョンとは異なる動作をするはずです。

これは、このページからの抜粋です(::absではなくstd::absを扱います):

double abs (double x); 
float abs (float x); 
long double abs (long double x);
Compute absolute value
/*
Returns the absolute value of x: |x|.
These convenience abs overloads are exclusive of C++. In C, abs is only declared
in  <cstdlib> (and operates on int values). 
The additional overloads are provided in this header (<cmath>) for the integral types: 
These overloads effectively cast x to a double before calculations 
(defined for T being any integral type).
*/

本当に???

ここではコンパイラと標準ライブラリの実装が異なるため、プログラムを新しいプラットフォームに移植するときに、これに悩まされてきました。

これが私のサンプルプログラムです:

#include <iostream>
//#include <stdlib.h>//Necessary inclusion compil under linux
//You can include either cmath or math.h, the result is the same
//#include <cmath>
#include <math.h>
int main(int argc, const char * argv[])
{
  double x = -1.5;
  double ax = std::abs(x);
  std::cout << "x=" << x << " ax=" << ax << std::endl;
  return 0;
}

そして、これがMSVC2010での結果です。

  • MSVC 2010ではコンパイルの警告は表示されず、math.hもstdlib.hも含まれていなくても、プログラムはコンパイルされます。math.hstdlib.hは常に含まれているようです。行う
  • プログラムの出力は次のとおりです。x=-1.5 ax=1.5(参照によると一見正しい)

これがOSXでの結果です。

  • -Wallフラグがあっても、コンパイル警告は発行されません(doubleからintへのキャストは通知されません)。 g++llvm-g++に置き換えても結果は同じです。コンパイルには、math.hまたはcmathを含める必要はありません。
  • プログラムの出力は次のとおりです。x=-1.5 ax=1

そして最後に、Linuxでの結果:

  • stdlib.hが含まれていない場合、プログラムはコンパイルされません(最後に、stdlibが自動的に含まれていないコンパイラが1つあります)。 double-> intキャストの場合、コンパイル警告は発行されません。
  • プログラムの出力は次のとおりです。x=-1.5 ax=1

ここに明確な勝者はありません。明白な答えは「std::absよりも::absを優先する」であることを私は知っていますが、私は疑問に思います:

  • absstd名前空間の外にダブルバージョンを自動的に提供する必要があると書かれている場合、cplusplus.com Webサイトはここにありますか?
  • MSVCを除くすべてのコンパイラとその標準ライブラリはここで間違っていますか(ただし、math.hはサイレントに含まれています)?
24
Pascal T.

公式の参考文献によると...それは混乱です。 Pre-C++ 11およびC11:

  • 公式には、<cmath>を含めて::には何も導入されていません。すべての関数はstd::にありました。実際には、exportだけがあまり尊重されておらず、コンパイラが異なれば、動作も大きく異なります。 <cmath>を含めた場合は、どこでもstd::を使用したか、コンパイラーごとに異なるものを使用しました。

  • Cはオーバーロードを提供しませんでした:absintを取り、<stdlib.h>で宣言され、fabsdoubleを取り、宣言されました<math.h>で。

  • C++に<math.h>を含めた場合、何が得られたかは明確ではありませんが、いずれの実装者も標準を気にしていないようでした(上記の最初のポイントを参照)...

大まかに言えば、<cmath>を含め、すべての用途の前にstd::を付けるか、<math.h>を含め、浮動小数点のサポートが必要な場合はfabsを使用しました( intまたはdouble以外のタイプのさまざまなサフィックス)。

C++ 11とC11は、いくつかの新しい工夫を追加しました。

  • <cmath>は、::にもシンボルを導入できるようになりました(必須ではありません)。実装によって異なる可能性のあるもう1つのこと。 (ここでの目標は、既存の実装を適合させることでした。)

  • Cには新しいヘッダー<tgmath.h>があり、コンパイラマジックを使用して、<math.h>の関数をC++のようにオーバーロードされているかのように動作させます。 (したがって、absには適用されず、fabsにのみ適用されます。)このヘッダーはnot C++に追加されました。これは、C++が適用されない明らかな理由によるものです。これにはコンパイラの魔法は必要ありません。

全体として、状況は少し悪化しており、上記の私の推奨事項は依然として有効です。 <math.h><stdlib.h>のいずれかを含め、abs/fabsとその派生物(例:labsfabsfなど)を使用します。 )排他的に、または<cmath>を含め、std::absを排他的に使用します。それ以外の場合は、移植性の問題が発生します。

34
James Kanze