真的需要<cmath>或<math.h>吗?没有它编译

cb1*_*295 3 c++ visual-studio

所以,我有以下代码,它构建和运行完美,尝试了各种值,一切都很好.您会注意到我使用log10函数,但我不包含cmath或math.h. 为什么它仍然可以构建并运行良好?这些图书馆真的需要吗?为什么/为什么不呢?是否与使用visual studio有关?比如,如果说我使用不同的IDE或命令提示符编译它会不会编译?

#include <iostream>
#include <iomanip>
using namespace std;

int main()  {

    cout << "Classify solutions as acidic or nonacidic" << endl<< endl;

    //declaring double molar concentration
    double mc = 1;

    //using while and if statements to calculate pH in fixed notaion and acidic  or nonacidic
    while (mc != 0)
    {
        cout << "Please enter a molar concentration (or enter 0 to exit): ";
        cin >> mc;

        if (mc != 0)
        {
            cout << "Molar Conentration = " << scientific << mc << endl; //scientific notation

            double pH = -log10(mc);
            cout << "pH = " << fixed << setprecision(6) << pH << endl;  //6 deciumals

            if (pH > 7)
            {
                cout << "Nonacidic" << endl << endl;
            }
            else if (pH < 7)
            {
                cout << "Acidic" << endl << endl;
            }
            else
                cout << "Neutral" << endl << endl;
        }
    }

    //end program when inputing 0
    cout << "End of Program" << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

pax*_*blo 6

代码:

i = i++ + ++i;
Run Code Online (Sandbox Code Playgroud)

可以编译好,但这不是一个好主意:-)

包含您使用的库函数的头文件是明智的.这样做不会丢失任何功能,但您确保功能可行(尽管有误用).


详细分析如下.

即使对此实施放宽,标准也要求它.C++11 17.6.2.2 Headers /3状态:

翻译单位应仅在任何外部声明或定义之外包括标题,并且应在该翻译单元中的第一次引用之前以词汇方式将标题包括在该标题中声明的任何实体之前.

gcc编译器,例如,会痛苦地抱怨你的代码:

xyzzy.cpp: In function 'int main()':
xyzzy.cpp:22:34: error: 'log10' was not declared in this scope
             double pH = -log10(mc);
                                  ^
Run Code Online (Sandbox Code Playgroud)

至于为什么VC++ 似乎违反了这个规则,它与允许头文件包含其他头文件这一事实有关.

如果您编译代码以生成预处理器输出(带/P),那么您将在其中找到深埋的线(至少在VS2013中):

#line 1 "c:\\blah\\blah\\vc\\include\\cmath"
Run Code Online (Sandbox Code Playgroud)

并且一些分析会出现以下包含层次结构:

iostream
    istream
        ostream
            ios
                xlocnum
                    cmath
Run Code Online (Sandbox Code Playgroud)

(<xlocnum>,使用的内部标题之一<locale>,似乎需要ldexp()来自<cmath>库,但也可能有其他标题).

VC++ 确实抱怨以下代码的事实进一步证明了这一点:

//#include <iostream>
using namespace std;

int main()  {
    double oneHundred = 100;
    int two = log10 (oneHundred);
    return two;
}
Run Code Online (Sandbox Code Playgroud)

有:

error C3861: 'log10': identifier not found
Run Code Online (Sandbox Code Playgroud)

但是,当您取消注释iostream包含线时,该错误就会消失.


但是,如前所述,这不是您应该依赖的行为.如果您要使用库函数(或宏/模板/其他),则由来包含正确的标题.

否则你的程序正确编译只是一个意外.

  • @ChristopherBonilla没有*保证*您的代码将成功编译.更改编译器,甚至使用其他版本的Visual Studio,如果不存在所需的标头,您的代码可能无法编译. (2认同)

Wil*_*ond 5

正如您所注意到的,您提供的代码片段在 Visual Studio 中有效,但在其他编译器中无效。这是因为标准库是如何为每个编译器实现的。

事实证明,当你有Visual Studio的实施<iostream>,你最终会包括很多其他的头间接地与这些头之一<cmath>

要查看确切的链,请导航到标准库包含目录。对我来说(我使用 Visual Studio 2013 社区版),它位于

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include

  1. 打开 iostream。注意行#include <istream>
  2. 打开 istream。注意行#include <ostream>
  3. 打开 ostream。注意行#include <ios>
  4. 打开ios。注意行#include <xlocnum>
  5. 打开 xlocnum。注意行#include <cmath>

你猜怎么着?您在包含 iostream 时包含了 cmath ......所以您的代码很好,至少在 Visual Studio 上。但是,不要依赖实现细节,否则如果您尝试将其迁移到另一个平台/工具链,您的代码将会中断。

例如,尝试在 Cygwin 上使用 g++ 编译提供的代码段会导致以下错误:

temp.cpp: In function ‘int main()’:
temp.cpp:22:34: error: ‘log10’ was not declared in this scope
             double pH = -log10(mc);
Run Code Online (Sandbox Code Playgroud)

这一定意味着 g++ 的实现<iostream>不依赖于<cmath>