简体   繁体   English

如果未为int定义sqrt()为什么在int变量上能正常工作?

[英]Why does sqrt() work fine on an int variable if it is not defined for an int?

In chapter 3 of Programming: Principles and Practice using C++ (sixth printing), Stroustrup states (p.68): "Note that sqrt() is not defined for an int " . 在《 编程:使用C ++的原理和实践》 (第六次印刷)的第3章中,Stroustrup指出(第68页): “请注意,没有为int定义sqrt()

Here is a simple C++ program based on that chapter: 这是基于该章的简单C ++程序:

#include "std_lib_facilities.h"

int main()
{
    int n = 3;
    cout << "Square root of n == " << sqrt(n) << "\n";
}

Given the quote above, I would expect the process of compiling or running this program to fail in some way. 鉴于以上引用,我希望编译或运行该程序的过程会在某种程度上失败。

To my surprise, compiling it (with g++ (GCC) 4.2.1) and running it succeeded without errors or warnings, and produced the following perfectly decent output: 令我惊讶的是,使用g ++(GCC(GCC)4.2.1)对其进行编译并运行成功,没有出现错误或警告,并产生了以下完美的输出:

Square root of n == 1.73205

My question therefore is: if sqrt() really is not defined for an int , then why doesn't the program above fail somehow? 因此,我的问题是:如果sqrt()确实没有为int定义,那么上面的程序为什么不以某种方式失败?

The 10 is being implicitly converted to a double. 10正在隐式转换为double。 This will happen automatically as long as you have the correct function prototype for sqrt. 只要您具有sqrt的正确函数原型,此操作就会自动发生。

Edit: beaten by comments 编辑:被评论打败

Update 2 更新2

This question was merged with an exact duplicate, on taking a look at this, the actual answer is much simpler than anyone originally thought. 将这个问题与一个完全重复的问题合并在一起,看看这个问题,实际答案比任何人最初想的都要简单得多。 The current version of std_lib_facilities.h includes the following line: 当前版本的std_lib_facilities.h包含以下行:

inline double sqrt(int x) { return sqrt(double(x)); }   // to match C++0x

which creates a specific overload for the int case to match what modern compilers should be be doing which is cast integer arguments to double , although this version does not cover all the cases. 这会为int情况创建一个特定的重载,以匹配现代编译器应做的工作,即将整数参数转换为double ,尽管此版本未涵盖所有情况。

If std_lib_facilities.h was not being used than the original logic still applies, although gcc-4.2 is rather old compared to Visual Studio 2012 from the original question but a 4.1.2 version have uses __builtin_sqrt specifically for the integer case. 如果未使用std_lib_facilities.h ,则原始逻辑仍然适用,尽管从原始问题来看,与Visual Studio 2012相比, gcc-4.2已经相当老了,但是4.1.2版本使用__builtin_sqrt专门用于整数情况。

Original 原版的

Since around 2005 the draft standard required integer argument to be cast to double this is covered in the draft C++ standard . 2005年左右开始 ,标准草案要求将整数参数强制转换两倍,这在C ++标准草案中已涉及。 If we look in section 26 Numerics library and then go to section 26.8 C library which covers the <cmath> header, it specifies overloads of the math functions for float , double and long double which is covered in paragraph 8 : 如果我们看一下第26 ,然后转到第26.8C库 ,它覆盖了<cmath>标头,它指定了floatdoublelong double的数学函数的重载,这在第8段中进行了介绍:

In addition to the double versions of the math functions in , C++ adds float and long double overloaded versions of these functions, with the same semantics. 除了中的数学函数的双重版本外,C ++还以相同的语义添加了这些函数的float和long double重载版本。

which would be ambiguous for the int case but the standard requires that sufficient overload are provided so that integer arguments are cast to double . 这将是ambiguousint情况,但该标准要求的是,提供足够的过载,使得整数参数被转换加倍 It is covered in paragraph 11 which says( emphasis mine ): 它在第11段中涉及( 强调我的 ):

Moreover, there shall be additional overloads sufficient to ensure: 此外,应有足够的额外过载来确保:

  1. If any arithmetic argument corresponding to a double parameter has type long double, then all arithmetic arguments corresponding to double parameters are effectively cast to long double. 如果对应于double参数的任何算术参数的类型为long double,则对应于double参数的所有算术参数都将有效地转换为long double。
  2. Otherwise, if any arithmetic argument corresponding to a double parameter has type double or an integer type, then all arithmetic arguments corresponding to double parameters are effectively cast to double. 否则,如果与double参数对应的任何算术参数具有double类型或整数类型, 则与double参数对应的所有算术参数都将有效地转换为double。
  3. Otherwise, all arithmetic arguments corresponding to double parameters have type float. 否则,所有与double参数相对应的算术参数都具有float类型。

Update 更新资料

As @nos points out it is possible that the version of sqrt being called is from math.h header as opposed to the overloads from cmath , if that is the case and there is likely a implementation defined caveat here then we may be reverting to old C style behavior if the only version available is sqrt(double) which would mean that int would be converted to double implicitly . 正如@nos指出的那样,被调用的sqrt版本可能来自math.h标头,而不是cmath的重载,如果是这种情况,并且有可能在此处定义实现 ,那么我们可能会恢复为旧如果唯一可用的版本是sqrt(double) ,则为C样式行为,这意味着int隐式转换为double

One way I found to test this on gcc and clang would be to use long type for a which along with -Wconversion flag triggers a warning for a potentially value altering conversion on my platform if we only have sqrt(double) available. 我发现在gccclang对此进行测试的一种方法是将long类型用于a ,如果我们只有sqrt(double)可用,它与-Wconversion标志一起触发在我的平台上可能更改值的警告。 Indeed if I include math.h instead of cmath we can produce this warning. 的确,如果我包括math.h而不是cmath我们可以产生此警告。 Although I can not trigger this behavior in clang which seems to indicate this is implementation dependent . 尽管我无法在clang中触发此行为,但这似乎表明这与实现有关

Because of implicit conversions . 由于隐式转换 sqrt is defined for double , and an int value can be (and is) converted implicitly to a value of type double . sqrt是为double定义的,并且可以将int值隐式转换为double类型的值。

(It is in fact pretty hard to prevent a function that takes a double from being called with an int . You may get your compiler to emit a warning, but since this is typically a value-preserving conversion, even that may be hard. C++ inherits from C the design to try as hard as possible to make code work, even if it requires contortions. Other languages are much stricter about this sort of thing.) (实际上很难阻止使用int调用需要使用double的函数。您可能会让编译器发出警告,但是由于这通常是一个保留值的转换,因此即使这样也可能很难。C ++从C继承了该设计以尽最大努力使代码工作,即使它需要扭曲。其他语言对此类型也要严格得多。

sqrt is defined for double . sqrt被定义为double And C++ allows you to convert int to double implicitly. C ++允许您将int隐式转换为double

int n = 3;
double x = sqrt(n);    // implicit conversion of n from int to double

Implicit conversions may happen when you use the value as a function parameter or assign it to a variable. 当您将该值用作函数参数或将其分配给变量时,可能会发生隐式转换。

An example for the second case would be: 第二种情况的示例是:

int n = 3;
double x = n;          // implicit conversion of n from int to double

Note that operators are also simply functions. 注意,运算符也只是函数。 Thus, you can also add an int to a double , which converts the int to a double before invoking the actual addition: 因此,您还可以在double添加一个int ,从而在调用实际的加法之前将int转换为double

int n = 3;
double x = 1.0;
double sum = n + x;    // implicit conversion of n from int to double

Because there's an implicit conversion from int to double . 因为存在从intdouble的隐式转换。

With the conversion, your code would look like this: 进行转换后,您的代码将如下所示:

cout << "Square root of n == " << sqrt((double)n) << "\n";

Because the compiler is actually automatically (ie "implicitly") converting the integer to a double (or maybe long double ) and sending that value to sqrt() . 因为编译器实际上是自动(即“隐式”)将整数转换为double (或者可能是long double )并将该值发送到sqrt() This is completely normally and completely legal. 这是完全正常和完全合法的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM